├── .eslintrc
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── bower.json
├── debug
├── simplemde.css
├── simplemde.debug.js
└── simplemde.js
├── dist
├── simplemde.min.css
└── simplemde.min.js
├── gulpfile.js
├── package.json
└── src
├── css
└── simplemde.css
└── js
├── codemirror
└── tablist.js
└── simplemde.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "indent": [
4 | 2,
5 | "tab"
6 | ],
7 | "strict": 0,
8 | "no-console": 0,
9 | "quotes": [
10 | 2,
11 | "double"
12 | ],
13 | "semi": [
14 | 2,
15 | "always"
16 | ]
17 | },
18 | "env": {
19 | "browser": true,
20 | "node":true
21 | },
22 | "extends": "eslint:recommended"
23 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | localtesting/
2 | node_modules/
3 | bower_components/
4 |
5 | #For IDE
6 | *.iml
7 | *.ipr
8 | *.iws
9 | .idea/
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '6'
4 | - '5'
5 | - '4'
6 | - '0.12'
7 | before_script:
8 | - npm install -g gulp
9 | script: gulp
10 | deploy:
11 | provider: npm
12 | email: support@nextstepwebs.com
13 | api_key:
14 | secure: nADZupyOhJAhTQgr5uOIydbDEjCTAj+3nGHW7ZBJUrVJcb0uR4pg8ngmwrUpvaCeNXgKPG9Uag75/mPcBre9ly2cigBIG9LHlxImlF8qi1jRJykcNRmBb9N2MJJj+zdAMwLaF5Ns+f2v3zt97qxovbEzunhXGcZeCaxc6y40nDM8OTyo0PESNBjQYqaNblt2gO2KHysrwFL8i4kCCKLa+HOBLu2iqgk/fYVqTmfhEeOiiwQ4lIXJeyPyzgb3OPhKCMV1FI5H0T48fRD0MPczt8ds3Daj1OjCbIZurQ7s1dcKwz1g6TKATN59HcMsSarW4lImrEeYmfQxz2F5NjKDRhnith5V0W2IssrkpDG9teTFQ20eQdl5cpnlGjgBvsjb8GhPLR44GvefyJL4+kJGI3O1KVq3/7wbmu/IXrvhtKHEQSdGL2PTqW8QxKasAoUCnk3LGZKN12g8bg0xDg2tvoCUk5Z3asHLRdCJpDbBq1h8QfZ4HV5VLYjr84xduOUZbEUtfMVAixPpJ4h1E3OXJ1wil97BlHjxOZ8JkkxJg5lgSUZ/O/QWwJokEAYXR9c+ouMoVokChAyleV77cRZ5qLn9zbnUxZtnKX8w0IUKeu95/z8QgiaRcERKVCpZvceo8Qw0Y+JoiEtno7Zg/nsrZGxsS6K/V3yg1QQmT3bjDHQ=
15 | on:
16 | tags: true
17 | repo: NextStepWebs/simplemde-markdown-editor
18 | branch: production
19 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ### Overview
2 | First of all, thanks for your interest in helping make SimpleMDE even better. Contributions help resolve rare bugs, accomplish neat new features, polish the code, and improve the documentation.
3 |
4 | ### Guidelines for contributing
5 | - The *most important* guideline for contributing is to compare against the `development` branch when creating a pull request. This allows time to test and modify code changes before merging them into the stable master branch with the next release.
6 | - Travis CI is configured to build and verify all PRs. If your PR causes the build to fail, please add an additional commit that resolves any problems.
7 | - If you really want to earn some brownie points, create a JSFiddle that demonstrates your code changes. Seriously, this helps immensely and allows one or multiple people to easily provide feedback on the great work you've done.
8 | - When creating the JSFiddle, keep in mind that you can use http://rawgit.com for your files.
9 | - Do your best to fully test your changes. Anticipate edge-case behavior.
10 | - Try to keep your codebase that you're making changes to as up-to-date as possible with the origin. SimpleMDE creates new releases frequently, so it's easy to fall behind if you've been working on something new for a while.
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Next Step Webs, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SimpleMDE - Markdown Editor
2 | A drop-in JavaScript textarea replacement for writing beautiful and understandable Markdown. The WYSIWYG-esque editor allows users who may be less experienced with Markdown to use familiar toolbar buttons and shortcuts. In addition, the syntax is rendered while editing to clearly show the expected result. Headings are larger, emphasized words are italicized, links are underlined, etc. SimpleMDE is one of the first editors to feature both built-in autosaving and spell checking.
3 |
4 | [**Demo**](https://simplemde.com)
5 |
6 | [](https://simplemde.com)
7 |
8 | ## Why not a WYSIWYG editor or pure Markdown?
9 | WYSIWYG editors that produce HTML are often complex and buggy. Markdown solves this problem in many ways, plus Markdown can be rendered natively on more platforms than HTML. However, Markdown is not a syntax that an average user will be familiar with, nor is it visually clear while editing. In otherwords, for an unfamiliar user, the syntax they write will make little sense until they click the preview button. SimpleMDE has been designed to bridge this gap for non-technical users who are less familiar with or just learning Markdown syntax.
10 |
11 | ## Install
12 |
13 | Via [npm](https://www.npmjs.com/package/simplemde).
14 | ```
15 | npm install simplemde --save
16 | ```
17 |
18 | Via [bower](https://www.bower.io).
19 | ```
20 | bower install simplemde --save
21 | ```
22 |
23 | Via [jsDelivr](https://www.jsdelivr.com/#!simplemde). *Please note, jsDelivr may take a few days to update to the latest release.*
24 |
25 | ```HTML
26 |
27 |
28 | ```
29 |
30 | ## Quick start
31 |
32 | After installing, load SimpleMDE on the first textarea on a page
33 |
34 | ```HTML
35 |
38 | ```
39 |
40 | #### Using a specific textarea
41 |
42 | Pure JavaScript method
43 |
44 | ```HTML
45 |
48 | ```
49 |
50 | jQuery method
51 |
52 | ```HTML
53 |
56 | ```
57 |
58 | ## Get/set the content
59 |
60 | ```JavaScript
61 | simplemde.value();
62 | ```
63 |
64 | ```JavaScript
65 | simplemde.value("This text will appear in the editor");
66 | ```
67 |
68 | ## Configuration
69 |
70 | - **autoDownloadFontAwesome**: If set to `true`, force downloads Font Awesome (used for icons). If set to `false`, prevents downloading. Defaults to `undefined`, which will intelligently check whether Font Awesome has already been included, then download accordingly.
71 | - **autofocus**: If set to `true`, autofocuses the editor. Defaults to `false`.
72 | - **autosave**: *Saves the text that's being written and will load it back in the future. It will forget the text when the form it's contained in is submitted.*
73 | - **enabled**: If set to `true`, autosave the text. Defaults to `false`.
74 | - **delay**: Delay between saves, in milliseconds. Defaults to `10000` (10s).
75 | - **uniqueId**: You must set a unique string identifier so that SimpleMDE can autosave. Something that separates this from other instances of SimpleMDE elsewhere on your website.
76 | - **blockStyles**: Customize how certain buttons that style blocks of text behave.
77 | - **bold** Can be set to `**` or `__`. Defaults to `**`.
78 | - **code** Can be set to ```` ``` ```` or `~~~`. Defaults to ```` ``` ````.
79 | - **italic** Can be set to `*` or `_`. Defaults to `*`.
80 | - **element**: The DOM element for the textarea to use. Defaults to the first textarea on the page.
81 | - **forceSync**: If set to `true`, force text changes made in SimpleMDE to be immediately stored in original textarea. Defaults to `false`.
82 | - **hideIcons**: An array of icon names to hide. Can be used to hide specific icons shown by default without completely customizing the toolbar.
83 | - **indentWithTabs**: If set to `false`, indent using spaces instead of tabs. Defaults to `true`.
84 | - **initialValue**: If set, will customize the initial value of the editor.
85 | - **insertTexts**: Customize how certain buttons that insert text behave. Takes an array with two elements. The first element will be the text inserted before the cursor or highlight, and the second element will be inserted after. For example, this is the default link value: `["[", "](http://)"]`.
86 | - horizontalRule
87 | - image
88 | - link
89 | - table
90 | - **lineWrapping**: If set to `false`, disable line wrapping. Defaults to `true`.
91 | - **parsingConfig**: Adjust settings for parsing the Markdown during editing (not previewing).
92 | - **allowAtxHeaderWithoutSpace**: If set to `true`, will render headers without a space after the `#`. Defaults to `false`.
93 | - **strikethrough**: If set to `false`, will not process GFM strikethrough syntax. Defaults to `true`.
94 | - **underscoresBreakWords**: If set to `true`, let underscores be a delimiter for separating words. Defaults to `false`.
95 | - **placeholder**: Custom placeholder that should be displayed
96 | - **previewRender**: Custom function for parsing the plaintext Markdown and returning HTML. Used when user previews.
97 | - **promptURLs**: If set to `true`, a JS alert window appears asking for the link or image URL. Defaults to `false`.
98 | - **renderingConfig**: Adjust settings for parsing the Markdown during previewing (not editing).
99 | - **singleLineBreaks**: If set to `false`, disable parsing GFM single line breaks. Defaults to `true`.
100 | - **codeSyntaxHighlighting**: If set to `true`, will highlight using [highlight.js](https://github.com/isagalaev/highlight.js). Defaults to `false`. To use this feature you must include highlight.js on your page. For example, include the script and the CSS files like:
``
``
101 | - **shortcuts**: Keyboard shortcuts associated with this instance. Defaults to the [array of shortcuts](#keyboard-shortcuts).
102 | - **showIcons**: An array of icon names to show. Can be used to show specific icons hidden by default without completely customizing the toolbar.
103 | - **spellChecker**: If set to `false`, disable the spell checker. Defaults to `true`.
104 | - **status**: If set to `false`, hide the status bar. Defaults to the array of built-in status bar items.
105 | - Optionally, you can set an array of status bar items to include, and in what order. You can even define your own custom status bar items.
106 | - **styleSelectedText**: If set to `false`, remove the `CodeMirror-selectedtext` class from selected lines. Defaults to `true`.
107 | - **tabSize**: If set, customize the tab size. Defaults to `2`.
108 | - **toolbar**: If set to `false`, hide the toolbar. Defaults to the [array of icons](#toolbar-icons).
109 | - **toolbarTips**: If set to `false`, disable toolbar button tips. Defaults to `true`.
110 |
111 | ```JavaScript
112 | // Most options demonstrate the non-default behavior
113 | var simplemde = new SimpleMDE({
114 | autofocus: true,
115 | autosave: {
116 | enabled: true,
117 | uniqueId: "MyUniqueID",
118 | delay: 1000,
119 | },
120 | blockStyles: {
121 | bold: "__",
122 | italic: "_"
123 | },
124 | element: document.getElementById("MyID"),
125 | forceSync: true,
126 | hideIcons: ["guide", "heading"],
127 | indentWithTabs: false,
128 | initialValue: "Hello world!",
129 | insertTexts: {
130 | horizontalRule: ["", "\n\n-----\n\n"],
131 | image: [""],
132 | link: ["[", "](http://)"],
133 | table: ["", "\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n"],
134 | },
135 | lineWrapping: false,
136 | parsingConfig: {
137 | allowAtxHeaderWithoutSpace: true,
138 | strikethrough: false,
139 | underscoresBreakWords: true,
140 | },
141 | placeholder: "Type here...",
142 | previewRender: function(plainText) {
143 | return customMarkdownParser(plainText); // Returns HTML from a custom parser
144 | },
145 | previewRender: function(plainText, preview) { // Async method
146 | setTimeout(function(){
147 | preview.innerHTML = customMarkdownParser(plainText);
148 | }, 250);
149 |
150 | return "Loading...";
151 | },
152 | promptURLs: true,
153 | renderingConfig: {
154 | singleLineBreaks: false,
155 | codeSyntaxHighlighting: true,
156 | },
157 | shortcuts: {
158 | drawTable: "Cmd-Alt-T"
159 | },
160 | showIcons: ["code", "table"],
161 | spellChecker: false,
162 | status: false,
163 | status: ["autosave", "lines", "words", "cursor"], // Optional usage
164 | status: ["autosave", "lines", "words", "cursor", {
165 | className: "keystrokes",
166 | defaultValue: function(el) {
167 | this.keystrokes = 0;
168 | el.innerHTML = "0 Keystrokes";
169 | },
170 | onUpdate: function(el) {
171 | el.innerHTML = ++this.keystrokes + " Keystrokes";
172 | }
173 | }], // Another optional usage, with a custom status bar item that counts keystrokes
174 | styleSelectedText: false,
175 | tabSize: 4,
176 | toolbar: false,
177 | toolbarTips: false,
178 | });
179 | ```
180 |
181 | #### Toolbar icons
182 |
183 | Below are the built-in toolbar icons (only some of which are enabled by default), which can be reorganized however you like. "Name" is the name of the icon, referenced in the JS. "Action" is either a function or a URL to open. "Class" is the class given to the icon. "Tooltip" is the small tooltip that appears via the `title=""` attribute. Note that shortcut hints are added automatically and reflect the specified action if it has a keybind assigned to it (i.e. with the value of `action` set to `bold` and that of `tooltip` set to `Bold`, the final text the user will see would be "Bold (Ctrl-B)").
184 |
185 | Additionally, you can add a separator between any icons by adding `"|"` to the toolbar array.
186 |
187 | Name | Action | Tooltip
Class
188 | :--- | :----- | :--------------
189 | bold | toggleBold | Bold
fa fa-bold
190 | italic | toggleItalic | Italic
fa fa-italic
191 | strikethrough | toggleStrikethrough | Strikethrough
fa fa-strikethrough
192 | heading | toggleHeadingSmaller | Heading
fa fa-header
193 | heading-smaller | toggleHeadingSmaller | Smaller Heading
fa fa-header
194 | heading-bigger | toggleHeadingBigger | Bigger Heading
fa fa-lg fa-header
195 | heading-1 | toggleHeading1 | Big Heading
fa fa-header fa-header-x fa-header-1
196 | heading-2 | toggleHeading2 | Medium Heading
fa fa-header fa-header-x fa-header-2
197 | heading-3 | toggleHeading3 | Small Heading
fa fa-header fa-header-x fa-header-3
198 | code | toggleCodeBlock | Code
fa fa-code
199 | quote | toggleBlockquote | Quote
fa fa-quote-left
200 | unordered-list | toggleUnorderedList | Generic List
fa fa-list-ul
201 | ordered-list | toggleOrderedList | Numbered List
fa fa-list-ol
202 | clean-block | cleanBlock | Clean block
fa fa-eraser fa-clean-block
203 | link | drawLink | Create Link
fa fa-link
204 | image | drawImage | Insert Image
fa fa-picture-o
205 | table | drawTable | Insert Table
fa fa-table
206 | horizontal-rule | drawHorizontalRule | Insert Horizontal Line
fa fa-minus
207 | preview | togglePreview | Toggle Preview
fa fa-eye no-disable
208 | side-by-side | toggleSideBySide | Toggle Side by Side
fa fa-columns no-disable no-mobile
209 | fullscreen | toggleFullScreen | Toggle Fullscreen
fa fa-arrows-alt no-disable no-mobile
210 | guide | [This link](https://simplemde.com/markdown-guide) | Markdown Guide
fa fa-question-circle
211 |
212 | Customize the toolbar using the `toolbar` option like:
213 |
214 | ```JavaScript
215 | // Customize only the order of existing buttons
216 | var simplemde = new SimpleMDE({
217 | toolbar: ["bold", "italic", "heading", "|", "quote"],
218 | });
219 |
220 | // Customize all information and/or add your own icons
221 | var simplemde = new SimpleMDE({
222 | toolbar: [{
223 | name: "bold",
224 | action: SimpleMDE.toggleBold,
225 | className: "fa fa-bold",
226 | title: "Bold",
227 | },
228 | {
229 | name: "custom",
230 | action: function customFunction(editor){
231 | // Add your own code
232 | },
233 | className: "fa fa-star",
234 | title: "Custom Button",
235 | },
236 | "|", // Separator
237 | ...
238 | ],
239 | });
240 | ```
241 |
242 | #### Keyboard shortcuts
243 |
244 | SimpleMDE comes with an array of predefined keyboard shortcuts, but they can be altered with a configuration option. The list of default ones is as follows:
245 |
246 | Shortcut | Action
247 | :------- | :-----
248 | *Cmd-'* | "toggleBlockquote"
249 | *Cmd-B* | "toggleBold"
250 | *Cmd-E* | "cleanBlock"
251 | *Cmd-H* | "toggleHeadingSmaller"
252 | *Cmd-I* | "toggleItalic"
253 | *Cmd-K* | "drawLink"
254 | *Cmd-L* | "toggleUnorderedList"
255 | *Cmd-P* | "togglePreview"
256 | *Cmd-Alt-C* | "toggleCodeBlock"
257 | *Cmd-Alt-I* | "drawImage"
258 | *Cmd-Alt-L* | "toggleOrderedList"
259 | *Shift-Cmd-H* | "toggleHeadingBigger"
260 | *F9* | "toggleSideBySide"
261 | *F11* | "toggleFullScreen"
262 |
263 | Here is how you can change a few, while leaving others untouched:
264 |
265 | ```JavaScript
266 | var simplemde = new SimpleMDE({
267 | shortcuts: {
268 | "toggleOrderedList": "Ctrl-Alt-K", // alter the shortcut for toggleOrderedList
269 | "toggleCodeBlock": null, // unbind Ctrl-Alt-C
270 | "drawTable": "Cmd-Alt-T" // bind Cmd-Alt-T to drawTable action, which doesn't come with a default shortcut
271 | }
272 | });
273 | ```
274 |
275 | Shortcuts are automatically converted between platforms. If you define a shortcut as "Cmd-B", on PC that shortcut will be changed to "Ctrl-B". Conversely, a shortcut defined as "Ctrl-B" will become "Cmd-B" for Mac users.
276 |
277 | The list of actions that can be bound is the same as the list of built-in actions available for [toolbar buttons](#toolbar-icons).
278 |
279 | #### Height
280 |
281 | To change the minimum height (before it starts auto-growing):
282 |
283 | ```CSS
284 | .CodeMirror, .CodeMirror-scroll {
285 | min-height: 200px;
286 | }
287 | ```
288 |
289 | Or, you can keep the height static:
290 |
291 | ```CSS
292 | .CodeMirror {
293 | height: 300px;
294 | }
295 | ```
296 |
297 | ## Event handling
298 | You can catch the following list of events: https://codemirror.net/doc/manual.html#events
299 |
300 | ```JavaScript
301 | var simplemde = new SimpleMDE();
302 | simplemde.codemirror.on("change", function(){
303 | console.log(simplemde.value());
304 | });
305 | ```
306 |
307 | ## Removing SimpleMDE from textarea
308 | You can revert to the initial textarea by calling the `toTextArea` method. Note that this clears up the autosave (if enabled) associated with it. The textarea will retain any text from the destroyed SimpleMDE instance.
309 |
310 | ```JavaScript
311 | var simplemde = new SimpleMDE();
312 | ...
313 | simplemde.toTextArea();
314 | simplemde = null;
315 | ```
316 |
317 | ## Useful methods
318 | The following self-explanatory methods may be of use while developing with SimpleMDE.
319 |
320 | ```js
321 | var simplemde = new SimpleMDE();
322 | simplemde.isPreviewActive(); // returns boolean
323 | simplemde.isSideBySideActive(); // returns boolean
324 | simplemde.isFullscreenActive(); // returns boolean
325 | simplemde.clearAutosavedValue(); // no returned value
326 | ```
327 |
328 | ## How it works
329 | SimpleMDE began as an improvement of [lepture's Editor project](https://github.com/lepture/editor), but has now taken on an identity of its own. It is bundled with [CodeMirror](https://github.com/codemirror/codemirror) and depends on [Font Awesome](http://fontawesome.io).
330 |
331 | CodeMirror is the backbone of the project and parses much of the Markdown syntax as it's being written. This allows us to add styles to the Markdown that's being written. Additionally, a toolbar and status bar have been added to the top and bottom, respectively. Previews are rendered by [Marked](https://github.com/chjj/marked) using GFM.
332 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "simplemde",
3 | "version": "1.11.2",
4 | "homepage": "https://github.com/NextStepWebs/simplemde-markdown-editor",
5 | "authors": [
6 | "Wes Cossick "
7 | ],
8 | "description": "A simple, beautiful, and embeddable JavaScript Markdown editor.",
9 | "main": ["src/js/simplemde.js", "src/css/simplemde.css"],
10 | "keywords": [
11 | "embeddable",
12 | "markdown",
13 | "editor",
14 | "javascript",
15 | "wysiwyg"
16 | ],
17 | "license": "MIT",
18 | "ignore": [
19 | "**/.*",
20 | "node_modules",
21 | "bower_components"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/debug/simplemde.css:
--------------------------------------------------------------------------------
1 | /**
2 | * simplemde v1.11.2
3 | * Copyright Next Step Webs, Inc.
4 | * @link https://github.com/NextStepWebs/simplemde-markdown-editor
5 | * @license MIT
6 | */
7 | /* BASICS */
8 |
9 | .CodeMirror {
10 | /* Set height, width, borders, and global font properties here */
11 | font-family: monospace;
12 | height: 300px;
13 | color: black;
14 | }
15 |
16 | /* PADDING */
17 |
18 | .CodeMirror-lines {
19 | padding: 4px 0; /* Vertical padding around content */
20 | }
21 | .CodeMirror pre {
22 | padding: 0 4px; /* Horizontal padding of content */
23 | }
24 |
25 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
26 | background-color: white; /* The little square between H and V scrollbars */
27 | }
28 |
29 | /* GUTTER */
30 |
31 | .CodeMirror-gutters {
32 | border-right: 1px solid #ddd;
33 | background-color: #f7f7f7;
34 | white-space: nowrap;
35 | }
36 | .CodeMirror-linenumbers {}
37 | .CodeMirror-linenumber {
38 | padding: 0 3px 0 5px;
39 | min-width: 20px;
40 | text-align: right;
41 | color: #999;
42 | white-space: nowrap;
43 | }
44 |
45 | .CodeMirror-guttermarker { color: black; }
46 | .CodeMirror-guttermarker-subtle { color: #999; }
47 |
48 | /* CURSOR */
49 |
50 | .CodeMirror-cursor {
51 | border-left: 1px solid black;
52 | border-right: none;
53 | width: 0;
54 | }
55 | /* Shown when moving in bi-directional text */
56 | .CodeMirror div.CodeMirror-secondarycursor {
57 | border-left: 1px solid silver;
58 | }
59 | .cm-fat-cursor .CodeMirror-cursor {
60 | width: auto;
61 | border: 0 !important;
62 | background: #7e7;
63 | }
64 | .cm-fat-cursor div.CodeMirror-cursors {
65 | z-index: 1;
66 | }
67 |
68 | .cm-animate-fat-cursor {
69 | width: auto;
70 | border: 0;
71 | -webkit-animation: blink 1.06s steps(1) infinite;
72 | -moz-animation: blink 1.06s steps(1) infinite;
73 | animation: blink 1.06s steps(1) infinite;
74 | background-color: #7e7;
75 | }
76 | @-moz-keyframes blink {
77 | 0% {}
78 | 50% { background-color: transparent; }
79 | 100% {}
80 | }
81 | @-webkit-keyframes blink {
82 | 0% {}
83 | 50% { background-color: transparent; }
84 | 100% {}
85 | }
86 | @keyframes blink {
87 | 0% {}
88 | 50% { background-color: transparent; }
89 | 100% {}
90 | }
91 |
92 | /* Can style cursor different in overwrite (non-insert) mode */
93 | .CodeMirror-overwrite .CodeMirror-cursor {}
94 |
95 | .cm-tab { display: inline-block; text-decoration: inherit; }
96 |
97 | .CodeMirror-ruler {
98 | border-left: 1px solid #ccc;
99 | position: absolute;
100 | }
101 |
102 | /* DEFAULT THEME */
103 |
104 | .cm-s-default .cm-header {color: blue;}
105 | .cm-s-default .cm-quote {color: #090;}
106 | .cm-negative {color: #d44;}
107 | .cm-positive {color: #292;}
108 | .cm-header, .cm-strong {font-weight: bold;}
109 | .cm-em {font-style: italic;}
110 | .cm-link {text-decoration: underline;}
111 | .cm-strikethrough {text-decoration: line-through;}
112 |
113 | .cm-s-default .cm-keyword {color: #708;}
114 | .cm-s-default .cm-atom {color: #219;}
115 | .cm-s-default .cm-number {color: #164;}
116 | .cm-s-default .cm-def {color: #00f;}
117 | .cm-s-default .cm-variable,
118 | .cm-s-default .cm-punctuation,
119 | .cm-s-default .cm-property,
120 | .cm-s-default .cm-operator {}
121 | .cm-s-default .cm-variable-2 {color: #05a;}
122 | .cm-s-default .cm-variable-3 {color: #085;}
123 | .cm-s-default .cm-comment {color: #a50;}
124 | .cm-s-default .cm-string {color: #a11;}
125 | .cm-s-default .cm-string-2 {color: #f50;}
126 | .cm-s-default .cm-meta {color: #555;}
127 | .cm-s-default .cm-qualifier {color: #555;}
128 | .cm-s-default .cm-builtin {color: #30a;}
129 | .cm-s-default .cm-bracket {color: #997;}
130 | .cm-s-default .cm-tag {color: #170;}
131 | .cm-s-default .cm-attribute {color: #00c;}
132 | .cm-s-default .cm-hr {color: #999;}
133 | .cm-s-default .cm-link {color: #00c;}
134 |
135 | .cm-s-default .cm-error {color: #f00;}
136 | .cm-invalidchar {color: #f00;}
137 |
138 | .CodeMirror-composing { border-bottom: 2px solid; }
139 |
140 | /* Default styles for common addons */
141 |
142 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
143 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
144 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
145 | .CodeMirror-activeline-background {background: #e8f2ff;}
146 |
147 | /* STOP */
148 |
149 | /* The rest of this file contains styles related to the mechanics of
150 | the editor. You probably shouldn't touch them. */
151 |
152 | .CodeMirror {
153 | position: relative;
154 | overflow: hidden;
155 | background: white;
156 | }
157 |
158 | .CodeMirror-scroll {
159 | overflow: scroll !important; /* Things will break if this is overridden */
160 | /* 30px is the magic margin used to hide the element's real scrollbars */
161 | /* See overflow: hidden in .CodeMirror */
162 | margin-bottom: -30px; margin-right: -30px;
163 | padding-bottom: 30px;
164 | height: 100%;
165 | outline: none; /* Prevent dragging from highlighting the element */
166 | position: relative;
167 | }
168 | .CodeMirror-sizer {
169 | position: relative;
170 | border-right: 30px solid transparent;
171 | }
172 |
173 | /* The fake, visible scrollbars. Used to force redraw during scrolling
174 | before actual scrolling happens, thus preventing shaking and
175 | flickering artifacts. */
176 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
177 | position: absolute;
178 | z-index: 6;
179 | display: none;
180 | }
181 | .CodeMirror-vscrollbar {
182 | right: 0; top: 0;
183 | overflow-x: hidden;
184 | overflow-y: scroll;
185 | }
186 | .CodeMirror-hscrollbar {
187 | bottom: 0; left: 0;
188 | overflow-y: hidden;
189 | overflow-x: scroll;
190 | }
191 | .CodeMirror-scrollbar-filler {
192 | right: 0; bottom: 0;
193 | }
194 | .CodeMirror-gutter-filler {
195 | left: 0; bottom: 0;
196 | }
197 |
198 | .CodeMirror-gutters {
199 | position: absolute; left: 0; top: 0;
200 | min-height: 100%;
201 | z-index: 3;
202 | }
203 | .CodeMirror-gutter {
204 | white-space: normal;
205 | height: 100%;
206 | display: inline-block;
207 | vertical-align: top;
208 | margin-bottom: -30px;
209 | /* Hack to make IE7 behave */
210 | *zoom:1;
211 | *display:inline;
212 | }
213 | .CodeMirror-gutter-wrapper {
214 | position: absolute;
215 | z-index: 4;
216 | background: none !important;
217 | border: none !important;
218 | }
219 | .CodeMirror-gutter-background {
220 | position: absolute;
221 | top: 0; bottom: 0;
222 | z-index: 4;
223 | }
224 | .CodeMirror-gutter-elt {
225 | position: absolute;
226 | cursor: default;
227 | z-index: 4;
228 | }
229 | .CodeMirror-gutter-wrapper {
230 | -webkit-user-select: none;
231 | -moz-user-select: none;
232 | user-select: none;
233 | }
234 |
235 | .CodeMirror-lines {
236 | cursor: text;
237 | min-height: 1px; /* prevents collapsing before first draw */
238 | }
239 | .CodeMirror pre {
240 | /* Reset some styles that the rest of the page might have set */
241 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
242 | border-width: 0;
243 | background: transparent;
244 | font-family: inherit;
245 | font-size: inherit;
246 | margin: 0;
247 | white-space: pre;
248 | word-wrap: normal;
249 | line-height: inherit;
250 | color: inherit;
251 | z-index: 2;
252 | position: relative;
253 | overflow: visible;
254 | -webkit-tap-highlight-color: transparent;
255 | -webkit-font-variant-ligatures: none;
256 | font-variant-ligatures: none;
257 | }
258 | .CodeMirror-wrap pre {
259 | word-wrap: break-word;
260 | white-space: pre-wrap;
261 | word-break: normal;
262 | }
263 |
264 | .CodeMirror-linebackground {
265 | position: absolute;
266 | left: 0; right: 0; top: 0; bottom: 0;
267 | z-index: 0;
268 | }
269 |
270 | .CodeMirror-linewidget {
271 | position: relative;
272 | z-index: 2;
273 | overflow: auto;
274 | }
275 |
276 | .CodeMirror-widget {}
277 |
278 | .CodeMirror-code {
279 | outline: none;
280 | }
281 |
282 | /* Force content-box sizing for the elements where we expect it */
283 | .CodeMirror-scroll,
284 | .CodeMirror-sizer,
285 | .CodeMirror-gutter,
286 | .CodeMirror-gutters,
287 | .CodeMirror-linenumber {
288 | -moz-box-sizing: content-box;
289 | box-sizing: content-box;
290 | }
291 |
292 | .CodeMirror-measure {
293 | position: absolute;
294 | width: 100%;
295 | height: 0;
296 | overflow: hidden;
297 | visibility: hidden;
298 | }
299 |
300 | .CodeMirror-cursor { position: absolute; }
301 | .CodeMirror-measure pre { position: static; }
302 |
303 | div.CodeMirror-cursors {
304 | visibility: hidden;
305 | position: relative;
306 | z-index: 3;
307 | }
308 | div.CodeMirror-dragcursors {
309 | visibility: visible;
310 | }
311 |
312 | .CodeMirror-focused div.CodeMirror-cursors {
313 | visibility: visible;
314 | }
315 |
316 | .CodeMirror-selected { background: #d9d9d9; }
317 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
318 | .CodeMirror-crosshair { cursor: crosshair; }
319 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
320 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
321 |
322 | .cm-searching {
323 | background: #ffa;
324 | background: rgba(255, 255, 0, .4);
325 | }
326 |
327 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
328 | .CodeMirror span { *vertical-align: text-bottom; }
329 |
330 | /* Used to force a border model for a node */
331 | .cm-force-border { padding-right: .1px; }
332 |
333 | @media print {
334 | /* Hide the cursor when printing */
335 | .CodeMirror div.CodeMirror-cursors {
336 | visibility: hidden;
337 | }
338 | }
339 |
340 | /* See issue #2901 */
341 | .cm-tab-wrap-hack:after { content: ''; }
342 |
343 | /* Help users use markselection to safely style text background */
344 | span.CodeMirror-selectedtext { background: none; }
345 |
346 | .CodeMirror {
347 | height: auto;
348 | min-height: 300px;
349 | border: 1px solid #ddd;
350 | border-bottom-left-radius: 4px;
351 | border-bottom-right-radius: 4px;
352 | padding: 10px;
353 | font: inherit;
354 | z-index: 1;
355 | }
356 |
357 | .CodeMirror-scroll {
358 | min-height: 300px
359 | }
360 |
361 | .CodeMirror-fullscreen {
362 | background: #fff;
363 | position: fixed !important;
364 | top: 50px;
365 | left: 0;
366 | right: 0;
367 | bottom: 0;
368 | height: auto;
369 | z-index: 9;
370 | }
371 |
372 | .CodeMirror-sided {
373 | width: 50% !important;
374 | }
375 |
376 | .editor-toolbar {
377 | position: relative;
378 | opacity: .6;
379 | -webkit-user-select: none;
380 | -moz-user-select: none;
381 | -ms-user-select: none;
382 | -o-user-select: none;
383 | user-select: none;
384 | padding: 0 10px;
385 | border-top: 1px solid #bbb;
386 | border-left: 1px solid #bbb;
387 | border-right: 1px solid #bbb;
388 | border-top-left-radius: 4px;
389 | border-top-right-radius: 4px;
390 | }
391 |
392 | .editor-toolbar:after,
393 | .editor-toolbar:before {
394 | display: block;
395 | content: ' ';
396 | height: 1px;
397 | }
398 |
399 | .editor-toolbar:before {
400 | margin-bottom: 8px
401 | }
402 |
403 | .editor-toolbar:after {
404 | margin-top: 8px
405 | }
406 |
407 | .editor-toolbar:hover,
408 | .editor-wrapper input.title:focus,
409 | .editor-wrapper input.title:hover {
410 | opacity: .8
411 | }
412 |
413 | .editor-toolbar.fullscreen {
414 | width: 100%;
415 | height: 50px;
416 | overflow-x: auto;
417 | overflow-y: hidden;
418 | white-space: nowrap;
419 | padding-top: 10px;
420 | padding-bottom: 10px;
421 | box-sizing: border-box;
422 | background: #fff;
423 | border: 0;
424 | position: fixed;
425 | top: 0;
426 | left: 0;
427 | opacity: 1;
428 | z-index: 9;
429 | }
430 |
431 | .editor-toolbar.fullscreen::before {
432 | width: 20px;
433 | height: 50px;
434 | background: -moz-linear-gradient(left, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
435 | background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 1)), color-stop(100%, rgba(255, 255, 255, 0)));
436 | background: -webkit-linear-gradient(left, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
437 | background: -o-linear-gradient(left, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
438 | background: -ms-linear-gradient(left, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
439 | background: linear-gradient(to right, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
440 | position: fixed;
441 | top: 0;
442 | left: 0;
443 | margin: 0;
444 | padding: 0;
445 | }
446 |
447 | .editor-toolbar.fullscreen::after {
448 | width: 20px;
449 | height: 50px;
450 | background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
451 | background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(100%, rgba(255, 255, 255, 1)));
452 | background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
453 | background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
454 | background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
455 | background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
456 | position: fixed;
457 | top: 0;
458 | right: 0;
459 | margin: 0;
460 | padding: 0;
461 | }
462 |
463 | .editor-toolbar a {
464 | display: inline-block;
465 | text-align: center;
466 | text-decoration: none!important;
467 | color: #2c3e50!important;
468 | width: 30px;
469 | height: 30px;
470 | margin: 0;
471 | border: 1px solid transparent;
472 | border-radius: 3px;
473 | cursor: pointer;
474 | }
475 |
476 | .editor-toolbar a.active,
477 | .editor-toolbar a:hover {
478 | background: #fcfcfc;
479 | border-color: #95a5a6;
480 | }
481 |
482 | .editor-toolbar a:before {
483 | line-height: 30px
484 | }
485 |
486 | .editor-toolbar i.separator {
487 | display: inline-block;
488 | width: 0;
489 | border-left: 1px solid #d9d9d9;
490 | border-right: 1px solid #fff;
491 | color: transparent;
492 | text-indent: -10px;
493 | margin: 0 6px;
494 | }
495 |
496 | .editor-toolbar a.fa-header-x:after {
497 | font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
498 | font-size: 65%;
499 | vertical-align: text-bottom;
500 | position: relative;
501 | top: 2px;
502 | }
503 |
504 | .editor-toolbar a.fa-header-1:after {
505 | content: "1";
506 | }
507 |
508 | .editor-toolbar a.fa-header-2:after {
509 | content: "2";
510 | }
511 |
512 | .editor-toolbar a.fa-header-3:after {
513 | content: "3";
514 | }
515 |
516 | .editor-toolbar a.fa-header-bigger:after {
517 | content: "▲";
518 | }
519 |
520 | .editor-toolbar a.fa-header-smaller:after {
521 | content: "▼";
522 | }
523 |
524 | .editor-toolbar.disabled-for-preview a:not(.no-disable) {
525 | pointer-events: none;
526 | background: #fff;
527 | border-color: transparent;
528 | text-shadow: inherit;
529 | }
530 |
531 | @media only screen and (max-width: 700px) {
532 | .editor-toolbar a.no-mobile {
533 | display: none;
534 | }
535 | }
536 |
537 | .editor-statusbar {
538 | padding: 8px 10px;
539 | font-size: 12px;
540 | color: #959694;
541 | text-align: right;
542 | }
543 |
544 | .editor-statusbar span {
545 | display: inline-block;
546 | min-width: 4em;
547 | margin-left: 1em;
548 | }
549 |
550 | .editor-statusbar .lines:before {
551 | content: 'lines: '
552 | }
553 |
554 | .editor-statusbar .words:before {
555 | content: 'words: '
556 | }
557 |
558 | .editor-statusbar .characters:before {
559 | content: 'characters: '
560 | }
561 |
562 | .editor-preview {
563 | padding: 10px;
564 | position: absolute;
565 | width: 100%;
566 | height: 100%;
567 | top: 0;
568 | left: 0;
569 | background: #fafafa;
570 | z-index: 7;
571 | overflow: auto;
572 | display: none;
573 | box-sizing: border-box;
574 | }
575 |
576 | .editor-preview-side {
577 | padding: 10px;
578 | position: fixed;
579 | bottom: 0;
580 | width: 50%;
581 | top: 50px;
582 | right: 0;
583 | background: #fafafa;
584 | z-index: 9;
585 | overflow: auto;
586 | display: none;
587 | box-sizing: border-box;
588 | border: 1px solid #ddd;
589 | }
590 |
591 | .editor-preview-active-side {
592 | display: block
593 | }
594 |
595 | .editor-preview-active {
596 | display: block
597 | }
598 |
599 | .editor-preview>p,
600 | .editor-preview-side>p {
601 | margin-top: 0
602 | }
603 |
604 | .editor-preview pre,
605 | .editor-preview-side pre {
606 | background: #eee;
607 | margin-bottom: 10px;
608 | }
609 |
610 | .editor-preview table td,
611 | .editor-preview table th,
612 | .editor-preview-side table td,
613 | .editor-preview-side table th {
614 | border: 1px solid #ddd;
615 | padding: 5px;
616 | }
617 |
618 | .CodeMirror .CodeMirror-code .cm-tag {
619 | color: #63a35c;
620 | }
621 |
622 | .CodeMirror .CodeMirror-code .cm-attribute {
623 | color: #795da3;
624 | }
625 |
626 | .CodeMirror .CodeMirror-code .cm-string {
627 | color: #183691;
628 | }
629 |
630 | .CodeMirror .CodeMirror-selected {
631 | background: #d9d9d9;
632 | }
633 |
634 | .CodeMirror .CodeMirror-code .cm-header-1 {
635 | font-size: 200%;
636 | line-height: 200%;
637 | }
638 |
639 | .CodeMirror .CodeMirror-code .cm-header-2 {
640 | font-size: 160%;
641 | line-height: 160%;
642 | }
643 |
644 | .CodeMirror .CodeMirror-code .cm-header-3 {
645 | font-size: 125%;
646 | line-height: 125%;
647 | }
648 |
649 | .CodeMirror .CodeMirror-code .cm-header-4 {
650 | font-size: 110%;
651 | line-height: 110%;
652 | }
653 |
654 | .CodeMirror .CodeMirror-code .cm-comment {
655 | background: rgba(0, 0, 0, .05);
656 | border-radius: 2px;
657 | }
658 |
659 | .CodeMirror .CodeMirror-code .cm-link {
660 | color: #7f8c8d;
661 | }
662 |
663 | .CodeMirror .CodeMirror-code .cm-url {
664 | color: #aab2b3;
665 | }
666 |
667 | .CodeMirror .CodeMirror-code .cm-strikethrough {
668 | text-decoration: line-through;
669 | }
670 |
671 | .CodeMirror .CodeMirror-placeholder {
672 | opacity: .5;
673 | }
674 | .CodeMirror .cm-spell-error:not(.cm-url):not(.cm-comment):not(.cm-tag):not(.cm-word) {
675 | background: rgba(255, 0, 0, .15);
676 | }
--------------------------------------------------------------------------------
/dist/simplemde.min.css:
--------------------------------------------------------------------------------
1 | /**
2 | * simplemde v1.11.2
3 | * Copyright Next Step Webs, Inc.
4 | * @link https://github.com/NextStepWebs/simplemde-markdown-editor
5 | * @license MIT
6 | */
7 | .CodeMirror{color:#000}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-ruler{border-left:1px solid #ccc;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-invalidchar,.cm-s-default .cm-error{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:none;font-variant-ligatures:none}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}.CodeMirror-focused div.CodeMirror-cursors,div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected,.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0}.CodeMirror{height:auto;min-height:300px;border:1px solid #ddd;border-bottom-left-radius:4px;border-bottom-right-radius:4px;padding:10px;font:inherit;z-index:1}.CodeMirror-scroll{min-height:300px}.CodeMirror-fullscreen{background:#fff;position:fixed!important;top:50px;left:0;right:0;bottom:0;height:auto;z-index:9}.CodeMirror-sided{width:50%!important}.editor-toolbar{position:relative;opacity:.6;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;padding:0 10px;border-top:1px solid #bbb;border-left:1px solid #bbb;border-right:1px solid #bbb;border-top-left-radius:4px;border-top-right-radius:4px}.editor-toolbar:after,.editor-toolbar:before{display:block;content:' ';height:1px}.editor-toolbar:before{margin-bottom:8px}.editor-toolbar:after{margin-top:8px}.editor-toolbar:hover,.editor-wrapper input.title:focus,.editor-wrapper input.title:hover{opacity:.8}.editor-toolbar.fullscreen{width:100%;height:50px;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-top:10px;padding-bottom:10px;box-sizing:border-box;background:#fff;border:0;position:fixed;top:0;left:0;opacity:1;z-index:9}.editor-toolbar.fullscreen::before{width:20px;height:50px;background:-moz-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(255,255,255,1)),color-stop(100%,rgba(255,255,255,0)));background:-webkit-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:-o-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:linear-gradient(to right,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);position:fixed;top:0;left:0;margin:0;padding:0}.editor-toolbar.fullscreen::after{width:20px;height:50px;background:-moz-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(255,255,255,0)),color-stop(100%,rgba(255,255,255,1)));background:-webkit-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:-o-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:-ms-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:linear-gradient(to right,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);position:fixed;top:0;right:0;margin:0;padding:0}.editor-toolbar a{display:inline-block;text-align:center;text-decoration:none!important;color:#2c3e50!important;width:30px;height:30px;margin:0;border:1px solid transparent;border-radius:3px;cursor:pointer}.editor-toolbar a.active,.editor-toolbar a:hover{background:#fcfcfc;border-color:#95a5a6}.editor-toolbar a:before{line-height:30px}.editor-toolbar i.separator{display:inline-block;width:0;border-left:1px solid #d9d9d9;border-right:1px solid #fff;color:transparent;text-indent:-10px;margin:0 6px}.editor-toolbar a.fa-header-x:after{font-family:Arial,"Helvetica Neue",Helvetica,sans-serif;font-size:65%;vertical-align:text-bottom;position:relative;top:2px}.editor-toolbar a.fa-header-1:after{content:"1"}.editor-toolbar a.fa-header-2:after{content:"2"}.editor-toolbar a.fa-header-3:after{content:"3"}.editor-toolbar a.fa-header-bigger:after{content:"▲"}.editor-toolbar a.fa-header-smaller:after{content:"▼"}.editor-toolbar.disabled-for-preview a:not(.no-disable){pointer-events:none;background:#fff;border-color:transparent;text-shadow:inherit}@media only screen and (max-width:700px){.editor-toolbar a.no-mobile{display:none}}.editor-statusbar{padding:8px 10px;font-size:12px;color:#959694;text-align:right}.editor-statusbar span{display:inline-block;min-width:4em;margin-left:1em}.editor-preview,.editor-preview-side{padding:10px;background:#fafafa;overflow:auto;display:none;box-sizing:border-box}.editor-statusbar .lines:before{content:'lines: '}.editor-statusbar .words:before{content:'words: '}.editor-statusbar .characters:before{content:'characters: '}.editor-preview{position:absolute;width:100%;height:100%;top:0;left:0;z-index:7}.editor-preview-side{position:fixed;bottom:0;width:50%;top:50px;right:0;z-index:9;border:1px solid #ddd}.editor-preview-active,.editor-preview-active-side{display:block}.editor-preview-side>p,.editor-preview>p{margin-top:0}.editor-preview pre,.editor-preview-side pre{background:#eee;margin-bottom:10px}.editor-preview table td,.editor-preview table th,.editor-preview-side table td,.editor-preview-side table th{border:1px solid #ddd;padding:5px}.CodeMirror .CodeMirror-code .cm-tag{color:#63a35c}.CodeMirror .CodeMirror-code .cm-attribute{color:#795da3}.CodeMirror .CodeMirror-code .cm-string{color:#183691}.CodeMirror .CodeMirror-selected{background:#d9d9d9}.CodeMirror .CodeMirror-code .cm-header-1{font-size:200%;line-height:200%}.CodeMirror .CodeMirror-code .cm-header-2{font-size:160%;line-height:160%}.CodeMirror .CodeMirror-code .cm-header-3{font-size:125%;line-height:125%}.CodeMirror .CodeMirror-code .cm-header-4{font-size:110%;line-height:110%}.CodeMirror .CodeMirror-code .cm-comment{background:rgba(0,0,0,.05);border-radius:2px}.CodeMirror .CodeMirror-code .cm-link{color:#7f8c8d}.CodeMirror .CodeMirror-code .cm-url{color:#aab2b3}.CodeMirror .CodeMirror-code .cm-strikethrough{text-decoration:line-through}.CodeMirror .CodeMirror-placeholder{opacity:.5}.CodeMirror .cm-spell-error:not(.cm-url):not(.cm-comment):not(.cm-tag):not(.cm-word){background:rgba(255,0,0,.15)}
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var gulp = require("gulp"),
4 | minifycss = require("gulp-clean-css"),
5 | uglify = require("gulp-uglify"),
6 | concat = require("gulp-concat"),
7 | header = require("gulp-header"),
8 | buffer = require("vinyl-buffer"),
9 | pkg = require("./package.json"),
10 | debug = require("gulp-debug"),
11 | eslint = require("gulp-eslint"),
12 | prettify = require("gulp-jsbeautifier"),
13 | browserify = require("browserify"),
14 | source = require("vinyl-source-stream"),
15 | rename = require("gulp-rename");
16 |
17 | var banner = ["/**",
18 | " * <%= pkg.name %> v<%= pkg.version %>",
19 | " * Copyright <%= pkg.company %>",
20 | " * @link <%= pkg.homepage %>",
21 | " * @license <%= pkg.license %>",
22 | " */",
23 | ""].join("\n");
24 |
25 | gulp.task("prettify-js", [], function() {
26 | return gulp.src("./src/js/simplemde.js")
27 | .pipe(prettify({js: {brace_style: "collapse", indent_char: "\t", indent_size: 1, max_preserve_newlines: 3, space_before_conditional: false}}))
28 | .pipe(gulp.dest("./src/js"));
29 | });
30 |
31 | gulp.task("prettify-css", [], function() {
32 | return gulp.src("./src/css/simplemde.css")
33 | .pipe(prettify({css: {indentChar: "\t", indentSize: 1}}))
34 | .pipe(gulp.dest("./src/css"));
35 | });
36 |
37 | gulp.task("lint", ["prettify-js"], function() {
38 | gulp.src("./src/js/**/*.js")
39 | .pipe(debug())
40 | .pipe(eslint())
41 | .pipe(eslint.format())
42 | .pipe(eslint.failAfterError());
43 | });
44 |
45 | function taskBrowserify(opts) {
46 | return browserify("./src/js/simplemde.js", opts)
47 | .bundle();
48 | }
49 |
50 | gulp.task("browserify:debug", ["lint"], function() {
51 | return taskBrowserify({debug:true, standalone:"SimpleMDE"})
52 | .pipe(source("simplemde.debug.js"))
53 | .pipe(buffer())
54 | .pipe(header(banner, {pkg: pkg}))
55 | .pipe(gulp.dest("./debug/"));
56 | });
57 |
58 | gulp.task("browserify", ["lint"], function() {
59 | return taskBrowserify({standalone:"SimpleMDE"})
60 | .pipe(source("simplemde.js"))
61 | .pipe(buffer())
62 | .pipe(header(banner, {pkg: pkg}))
63 | .pipe(gulp.dest("./debug/"));
64 | });
65 |
66 | gulp.task("scripts", ["browserify:debug", "browserify", "lint"], function() {
67 | var js_files = ["./debug/simplemde.js"];
68 |
69 | return gulp.src(js_files)
70 | .pipe(concat("simplemde.min.js"))
71 | .pipe(uglify())
72 | .pipe(buffer())
73 | .pipe(header(banner, {pkg: pkg}))
74 | .pipe(gulp.dest("./dist/"));
75 | });
76 |
77 | gulp.task("styles", ["prettify-css"], function() {
78 | var css_files = [
79 | "./node_modules/codemirror/lib/codemirror.css",
80 | "./src/css/*.css",
81 | "./node_modules/codemirror-spell-checker/src/css/spell-checker.css"
82 | ];
83 |
84 | return gulp.src(css_files)
85 | .pipe(concat("simplemde.css"))
86 | .pipe(buffer())
87 | .pipe(header(banner, {pkg: pkg}))
88 | .pipe(gulp.dest("./debug/"))
89 | .pipe(minifycss())
90 | .pipe(rename("simplemde.min.css"))
91 | .pipe(buffer())
92 | .pipe(header(banner, {pkg: pkg}))
93 | .pipe(gulp.dest("./dist/"));
94 | });
95 |
96 | gulp.task("default", ["scripts", "styles"]);
97 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "simplemde",
3 | "version": "1.11.2",
4 | "description": "A simple, beautiful, and embeddable JavaScript Markdown editor. Features autosaving and spell checking.",
5 | "keywords": [
6 | "embeddable",
7 | "markdown",
8 | "editor",
9 | "javascript",
10 | "wysiwyg"
11 | ],
12 | "homepage": "https://github.com/NextStepWebs/simplemde-markdown-editor",
13 | "main": "./src/js/simplemde.js",
14 | "license": "MIT",
15 | "company": "Next Step Webs, Inc.",
16 | "author": {
17 | "name": "Wes Cossick",
18 | "url": "http://www.WesCossick.com"
19 | },
20 | "bugs": {
21 | "url": "https://github.com/NextStepWebs/simplemde-markdown-editor/issues"
22 | },
23 | "dependencies": {
24 | "codemirror": "*",
25 | "codemirror-spell-checker": "*",
26 | "marked": "*"
27 | },
28 | "devDependencies": {
29 | "browserify": "*",
30 | "debug": "*",
31 | "eslint": "*",
32 | "gulp": "*",
33 | "gulp-concat": "*",
34 | "gulp-debug": "*",
35 | "gulp-eslint": "*",
36 | "gulp-header": "*",
37 | "gulp-jsbeautifier": "*",
38 | "gulp-clean-css": "*",
39 | "gulp-rename": "*",
40 | "gulp-uglify": "*",
41 | "vinyl-source-stream": "*",
42 | "vinyl-buffer": "*"
43 | },
44 | "repository": {
45 | "type": "git",
46 | "url": "https://github.com/NextStepWebs/simplemde-markdown-editor"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/css/simplemde.css:
--------------------------------------------------------------------------------
1 | .CodeMirror {
2 | height: auto;
3 | min-height: 300px;
4 | border: 1px solid #ddd;
5 | border-bottom-left-radius: 4px;
6 | border-bottom-right-radius: 4px;
7 | padding: 10px;
8 | font: inherit;
9 | z-index: 1;
10 | }
11 |
12 | .CodeMirror-scroll {
13 | min-height: 300px
14 | }
15 |
16 | .CodeMirror-fullscreen {
17 | background: #fff;
18 | position: fixed !important;
19 | top: 50px;
20 | left: 0;
21 | right: 0;
22 | bottom: 0;
23 | height: auto;
24 | z-index: 9;
25 | }
26 |
27 | .CodeMirror-sided {
28 | width: 50% !important;
29 | }
30 |
31 | .editor-toolbar {
32 | position: relative;
33 | opacity: .6;
34 | -webkit-user-select: none;
35 | -moz-user-select: none;
36 | -ms-user-select: none;
37 | -o-user-select: none;
38 | user-select: none;
39 | padding: 0 10px;
40 | border-top: 1px solid #bbb;
41 | border-left: 1px solid #bbb;
42 | border-right: 1px solid #bbb;
43 | border-top-left-radius: 4px;
44 | border-top-right-radius: 4px;
45 | }
46 |
47 | .editor-toolbar:after,
48 | .editor-toolbar:before {
49 | display: block;
50 | content: ' ';
51 | height: 1px;
52 | }
53 |
54 | .editor-toolbar:before {
55 | margin-bottom: 8px
56 | }
57 |
58 | .editor-toolbar:after {
59 | margin-top: 8px
60 | }
61 |
62 | .editor-toolbar:hover,
63 | .editor-wrapper input.title:focus,
64 | .editor-wrapper input.title:hover {
65 | opacity: .8
66 | }
67 |
68 | .editor-toolbar.fullscreen {
69 | width: 100%;
70 | height: 50px;
71 | overflow-x: auto;
72 | overflow-y: hidden;
73 | white-space: nowrap;
74 | padding-top: 10px;
75 | padding-bottom: 10px;
76 | box-sizing: border-box;
77 | background: #fff;
78 | border: 0;
79 | position: fixed;
80 | top: 0;
81 | left: 0;
82 | opacity: 1;
83 | z-index: 9;
84 | }
85 |
86 | .editor-toolbar.fullscreen::before {
87 | width: 20px;
88 | height: 50px;
89 | background: -moz-linear-gradient(left, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
90 | background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 1)), color-stop(100%, rgba(255, 255, 255, 0)));
91 | background: -webkit-linear-gradient(left, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
92 | background: -o-linear-gradient(left, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
93 | background: -ms-linear-gradient(left, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
94 | background: linear-gradient(to right, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
95 | position: fixed;
96 | top: 0;
97 | left: 0;
98 | margin: 0;
99 | padding: 0;
100 | }
101 |
102 | .editor-toolbar.fullscreen::after {
103 | width: 20px;
104 | height: 50px;
105 | background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
106 | background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(100%, rgba(255, 255, 255, 1)));
107 | background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
108 | background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
109 | background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
110 | background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
111 | position: fixed;
112 | top: 0;
113 | right: 0;
114 | margin: 0;
115 | padding: 0;
116 | }
117 |
118 | .editor-toolbar a {
119 | display: inline-block;
120 | text-align: center;
121 | text-decoration: none!important;
122 | color: #2c3e50!important;
123 | width: 30px;
124 | height: 30px;
125 | margin: 0;
126 | border: 1px solid transparent;
127 | border-radius: 3px;
128 | cursor: pointer;
129 | }
130 |
131 | .editor-toolbar a.active,
132 | .editor-toolbar a:hover {
133 | background: #fcfcfc;
134 | border-color: #95a5a6;
135 | }
136 |
137 | .editor-toolbar a:before {
138 | line-height: 30px
139 | }
140 |
141 | .editor-toolbar i.separator {
142 | display: inline-block;
143 | width: 0;
144 | border-left: 1px solid #d9d9d9;
145 | border-right: 1px solid #fff;
146 | color: transparent;
147 | text-indent: -10px;
148 | margin: 0 6px;
149 | }
150 |
151 | .editor-toolbar a.fa-header-x:after {
152 | font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
153 | font-size: 65%;
154 | vertical-align: text-bottom;
155 | position: relative;
156 | top: 2px;
157 | }
158 |
159 | .editor-toolbar a.fa-header-1:after {
160 | content: "1";
161 | }
162 |
163 | .editor-toolbar a.fa-header-2:after {
164 | content: "2";
165 | }
166 |
167 | .editor-toolbar a.fa-header-3:after {
168 | content: "3";
169 | }
170 |
171 | .editor-toolbar a.fa-header-bigger:after {
172 | content: "▲";
173 | }
174 |
175 | .editor-toolbar a.fa-header-smaller:after {
176 | content: "▼";
177 | }
178 |
179 | .editor-toolbar.disabled-for-preview a:not(.no-disable) {
180 | pointer-events: none;
181 | background: #fff;
182 | border-color: transparent;
183 | text-shadow: inherit;
184 | }
185 |
186 | @media only screen and (max-width: 700px) {
187 | .editor-toolbar a.no-mobile {
188 | display: none;
189 | }
190 | }
191 |
192 | .editor-statusbar {
193 | padding: 8px 10px;
194 | font-size: 12px;
195 | color: #959694;
196 | text-align: right;
197 | }
198 |
199 | .editor-statusbar span {
200 | display: inline-block;
201 | min-width: 4em;
202 | margin-left: 1em;
203 | }
204 |
205 | .editor-statusbar .lines:before {
206 | content: 'lines: '
207 | }
208 |
209 | .editor-statusbar .words:before {
210 | content: 'words: '
211 | }
212 |
213 | .editor-statusbar .characters:before {
214 | content: 'characters: '
215 | }
216 |
217 | .editor-preview {
218 | padding: 10px;
219 | position: absolute;
220 | width: 100%;
221 | height: 100%;
222 | top: 0;
223 | left: 0;
224 | background: #fafafa;
225 | z-index: 7;
226 | overflow: auto;
227 | display: none;
228 | box-sizing: border-box;
229 | }
230 |
231 | .editor-preview-side {
232 | padding: 10px;
233 | position: fixed;
234 | bottom: 0;
235 | width: 50%;
236 | top: 50px;
237 | right: 0;
238 | background: #fafafa;
239 | z-index: 9;
240 | overflow: auto;
241 | display: none;
242 | box-sizing: border-box;
243 | border: 1px solid #ddd;
244 | }
245 |
246 | .editor-preview-active-side {
247 | display: block
248 | }
249 |
250 | .editor-preview-active {
251 | display: block
252 | }
253 |
254 | .editor-preview>p,
255 | .editor-preview-side>p {
256 | margin-top: 0
257 | }
258 |
259 | .editor-preview pre,
260 | .editor-preview-side pre {
261 | background: #eee;
262 | margin-bottom: 10px;
263 | }
264 |
265 | .editor-preview table td,
266 | .editor-preview table th,
267 | .editor-preview-side table td,
268 | .editor-preview-side table th {
269 | border: 1px solid #ddd;
270 | padding: 5px;
271 | }
272 |
273 | .CodeMirror .CodeMirror-code .cm-tag {
274 | color: #63a35c;
275 | }
276 |
277 | .CodeMirror .CodeMirror-code .cm-attribute {
278 | color: #795da3;
279 | }
280 |
281 | .CodeMirror .CodeMirror-code .cm-string {
282 | color: #183691;
283 | }
284 |
285 | .CodeMirror .CodeMirror-selected {
286 | background: #d9d9d9;
287 | }
288 |
289 | .CodeMirror .CodeMirror-code .cm-header-1 {
290 | font-size: 200%;
291 | line-height: 200%;
292 | }
293 |
294 | .CodeMirror .CodeMirror-code .cm-header-2 {
295 | font-size: 160%;
296 | line-height: 160%;
297 | }
298 |
299 | .CodeMirror .CodeMirror-code .cm-header-3 {
300 | font-size: 125%;
301 | line-height: 125%;
302 | }
303 |
304 | .CodeMirror .CodeMirror-code .cm-header-4 {
305 | font-size: 110%;
306 | line-height: 110%;
307 | }
308 |
309 | .CodeMirror .CodeMirror-code .cm-comment {
310 | background: rgba(0, 0, 0, .05);
311 | border-radius: 2px;
312 | }
313 |
314 | .CodeMirror .CodeMirror-code .cm-link {
315 | color: #7f8c8d;
316 | }
317 |
318 | .CodeMirror .CodeMirror-code .cm-url {
319 | color: #aab2b3;
320 | }
321 |
322 | .CodeMirror .CodeMirror-code .cm-strikethrough {
323 | text-decoration: line-through;
324 | }
325 |
326 | .CodeMirror .CodeMirror-placeholder {
327 | opacity: .5;
328 | }
--------------------------------------------------------------------------------
/src/js/codemirror/tablist.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | var CodeMirror = require("codemirror");
5 |
6 | CodeMirror.commands.tabAndIndentMarkdownList = function (cm) {
7 | var ranges = cm.listSelections();
8 | var pos = ranges[0].head;
9 | var eolState = cm.getStateAfter(pos.line);
10 | var inList = eolState.list !== false;
11 |
12 | if (inList) {
13 | cm.execCommand("indentMore");
14 | return;
15 | }
16 |
17 | if (cm.options.indentWithTabs) {
18 | cm.execCommand("insertTab");
19 | }
20 | else {
21 | var spaces = Array(cm.options.tabSize + 1).join(" ");
22 | cm.replaceSelection(spaces);
23 | }
24 | };
25 |
26 | CodeMirror.commands.shiftTabAndUnindentMarkdownList = function (cm) {
27 | var ranges = cm.listSelections();
28 | var pos = ranges[0].head;
29 | var eolState = cm.getStateAfter(pos.line);
30 | var inList = eolState.list !== false;
31 |
32 | if (inList) {
33 | cm.execCommand("indentLess");
34 | return;
35 | }
36 |
37 | if (cm.options.indentWithTabs) {
38 | cm.execCommand("insertTab");
39 | }
40 | else {
41 | var spaces = Array(cm.options.tabSize + 1).join(" ");
42 | cm.replaceSelection(spaces);
43 | }
44 | };
45 |
--------------------------------------------------------------------------------
/src/js/simplemde.js:
--------------------------------------------------------------------------------
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 | var marked = require("marked");
15 |
16 |
17 | // Some variables
18 | var isMac = /Mac/.test(navigator.platform);
19 |
20 | // Mapping of actions that can be bound to keyboard shortcuts or toolbar buttons
21 | var bindings = {
22 | "toggleBold": toggleBold,
23 | "toggleItalic": toggleItalic,
24 | "drawLink": drawLink,
25 | "toggleHeadingSmaller": toggleHeadingSmaller,
26 | "toggleHeadingBigger": toggleHeadingBigger,
27 | "drawImage": drawImage,
28 | "toggleBlockquote": toggleBlockquote,
29 | "toggleOrderedList": toggleOrderedList,
30 | "toggleUnorderedList": toggleUnorderedList,
31 | "toggleCodeBlock": toggleCodeBlock,
32 | "togglePreview": togglePreview,
33 | "toggleStrikethrough": toggleStrikethrough,
34 | "toggleHeading1": toggleHeading1,
35 | "toggleHeading2": toggleHeading2,
36 | "toggleHeading3": toggleHeading3,
37 | "cleanBlock": cleanBlock,
38 | "drawTable": drawTable,
39 | "drawHorizontalRule": drawHorizontalRule,
40 | "undo": undo,
41 | "redo": redo,
42 | "toggleSideBySide": toggleSideBySide,
43 | "toggleFullScreen": toggleFullScreen
44 | };
45 |
46 | var shortcuts = {
47 | "toggleBold": "Cmd-B",
48 | "toggleItalic": "Cmd-I",
49 | "drawLink": "Cmd-K",
50 | "toggleHeadingSmaller": "Cmd-H",
51 | "toggleHeadingBigger": "Shift-Cmd-H",
52 | "cleanBlock": "Cmd-E",
53 | "drawImage": "Cmd-Alt-I",
54 | "toggleBlockquote": "Cmd-'",
55 | "toggleOrderedList": "Cmd-Alt-L",
56 | "toggleUnorderedList": "Cmd-L",
57 | "toggleCodeBlock": "Cmd-Alt-C",
58 | "togglePreview": "Cmd-P",
59 | "toggleSideBySide": "F9",
60 | "toggleFullScreen": "F11"
61 | };
62 |
63 | var getBindingName = function(f) {
64 | for(var key in bindings) {
65 | if(bindings[key] === f) {
66 | return key;
67 | }
68 | }
69 | return null;
70 | };
71 |
72 | var isMobile = function() {
73 | var check = false;
74 | (function(a) {
75 | 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;
76 | })(navigator.userAgent || navigator.vendor || window.opera);
77 | return check;
78 | };
79 |
80 |
81 | /**
82 | * Fix shortcut. Mac use Command, others use Ctrl.
83 | */
84 | function fixShortcut(name) {
85 | if(isMac) {
86 | name = name.replace("Ctrl", "Cmd");
87 | } else {
88 | name = name.replace("Cmd", "Ctrl");
89 | }
90 | return name;
91 | }
92 |
93 |
94 | /**
95 | * Create icon element for toolbar.
96 | */
97 | function createIcon(options, enableTooltips, shortcuts) {
98 | options = options || {};
99 | var el = document.createElement("a");
100 | enableTooltips = (enableTooltips == undefined) ? true : enableTooltips;
101 |
102 | if(options.title && enableTooltips) {
103 | el.title = createTootlip(options.title, options.action, shortcuts);
104 |
105 | if(isMac) {
106 | el.title = el.title.replace("Ctrl", "⌘");
107 | el.title = el.title.replace("Alt", "⌥");
108 | }
109 | }
110 |
111 | el.tabIndex = -1;
112 | el.className = options.className;
113 | return el;
114 | }
115 |
116 | function createSep() {
117 | var el = document.createElement("i");
118 | el.className = "separator";
119 | el.innerHTML = "|";
120 | return el;
121 | }
122 |
123 | function createTootlip(title, action, shortcuts) {
124 | var actionName;
125 | var tooltip = title;
126 |
127 | if(action) {
128 | actionName = getBindingName(action);
129 | if(shortcuts[actionName]) {
130 | tooltip += " (" + fixShortcut(shortcuts[actionName]) + ")";
131 | }
132 | }
133 |
134 | return tooltip;
135 | }
136 |
137 | /**
138 | * The state of CodeMirror at the given position.
139 | */
140 | function getState(cm, pos) {
141 | pos = pos || cm.getCursor("start");
142 | var stat = cm.getTokenAt(pos);
143 | if(!stat.type) return {};
144 |
145 | var types = stat.type.split(" ");
146 |
147 | var ret = {},
148 | data, text;
149 | for(var i = 0; i < types.length; i++) {
150 | data = types[i];
151 | if(data === "strong") {
152 | ret.bold = true;
153 | } else if(data === "variable-2") {
154 | text = cm.getLine(pos.line);
155 | if(/^\s*\d+\.\s/.test(text)) {
156 | ret["ordered-list"] = true;
157 | } else {
158 | ret["unordered-list"] = true;
159 | }
160 | } else if(data === "atom") {
161 | ret.quote = true;
162 | } else if(data === "em") {
163 | ret.italic = true;
164 | } else if(data === "quote") {
165 | ret.quote = true;
166 | } else if(data === "strikethrough") {
167 | ret.strikethrough = true;
168 | } else if(data === "comment") {
169 | ret.code = true;
170 | } else if(data === "link") {
171 | ret.link = true;
172 | } else if(data === "tag") {
173 | ret.image = true;
174 | } else if(data.match(/^header(\-[1-6])?$/)) {
175 | ret[data.replace("header", "heading")] = true;
176 | }
177 | }
178 | return ret;
179 | }
180 |
181 |
182 | // Saved overflow setting
183 | var saved_overflow = "";
184 |
185 | /**
186 | * Toggle full screen of the editor.
187 | */
188 | function toggleFullScreen(editor) {
189 | // Set fullscreen
190 | var cm = editor.codemirror;
191 | cm.setOption("fullScreen", !cm.getOption("fullScreen"));
192 |
193 |
194 | // Prevent scrolling on body during fullscreen active
195 | if(cm.getOption("fullScreen")) {
196 | saved_overflow = document.body.style.overflow;
197 | document.body.style.overflow = "hidden";
198 | } else {
199 | document.body.style.overflow = saved_overflow;
200 | }
201 |
202 |
203 | // Update toolbar class
204 | var wrap = cm.getWrapperElement();
205 |
206 | if(!/fullscreen/.test(wrap.previousSibling.className)) {
207 | wrap.previousSibling.className += " fullscreen";
208 | } else {
209 | wrap.previousSibling.className = wrap.previousSibling.className.replace(/\s*fullscreen\b/, "");
210 | }
211 |
212 |
213 | // Update toolbar button
214 | var toolbarButton = editor.toolbarElements.fullscreen;
215 |
216 | if(!/active/.test(toolbarButton.className)) {
217 | toolbarButton.className += " active";
218 | } else {
219 | toolbarButton.className = toolbarButton.className.replace(/\s*active\s*/g, "");
220 | }
221 |
222 |
223 | // Hide side by side if needed
224 | var sidebyside = cm.getWrapperElement().nextSibling;
225 | if(/editor-preview-active-side/.test(sidebyside.className))
226 | toggleSideBySide(editor);
227 | }
228 |
229 |
230 | /**
231 | * Action for toggling bold.
232 | */
233 | function toggleBold(editor) {
234 | _toggleBlock(editor, "bold", editor.options.blockStyles.bold);
235 | }
236 |
237 |
238 | /**
239 | * Action for toggling italic.
240 | */
241 | function toggleItalic(editor) {
242 | _toggleBlock(editor, "italic", editor.options.blockStyles.italic);
243 | }
244 |
245 |
246 | /**
247 | * Action for toggling strikethrough.
248 | */
249 | function toggleStrikethrough(editor) {
250 | _toggleBlock(editor, "strikethrough", "~~");
251 | }
252 |
253 | /**
254 | * Action for toggling code block.
255 | */
256 | function toggleCodeBlock(editor) {
257 | var fenceCharsToInsert = editor.options.blockStyles.code;
258 |
259 | function fencing_line(line) {
260 | /* return true, if this is a ``` or ~~~ line */
261 | if(typeof line !== "object") {
262 | throw "fencing_line() takes a 'line' object (not a line number, or line text). Got: " + typeof line + ": " + line;
263 | }
264 | return line.styles && line.styles[2] && line.styles[2].indexOf("formatting-code-block") !== -1;
265 | }
266 |
267 | function token_state(token) {
268 | // base goes an extra level deep when mode backdrops are used, e.g. spellchecker on
269 | return token.state.base.base || token.state.base;
270 | }
271 |
272 | function code_type(cm, line_num, line, firstTok, lastTok) {
273 | /*
274 | * Return "single", "indented", "fenced" or false
275 | *
276 | * cm and line_num are required. Others are optional for efficiency
277 | * To check in the middle of a line, pass in firstTok yourself.
278 | */
279 | line = line || cm.getLineHandle(line_num);
280 | firstTok = firstTok || cm.getTokenAt({
281 | line: line_num,
282 | ch: 1
283 | });
284 | lastTok = lastTok || (!!line.text && cm.getTokenAt({
285 | line: line_num,
286 | ch: line.text.length - 1
287 | }));
288 | var types = firstTok.type ? firstTok.type.split(" ") : [];
289 | if(lastTok && token_state(lastTok).indentedCode) {
290 | // have to check last char, since first chars of first line aren"t marked as indented
291 | return "indented";
292 | } else if(types.indexOf("comment") === -1) {
293 | // has to be after "indented" check, since first chars of first indented line aren"t marked as such
294 | return false;
295 | } else if(token_state(firstTok).fencedChars || token_state(lastTok).fencedChars || fencing_line(line)) {
296 | return "fenced";
297 | } else {
298 | return "single";
299 | }
300 | }
301 |
302 | function insertFencingAtSelection(cm, cur_start, cur_end, fenceCharsToInsert) {
303 | var start_line_sel = cur_start.line + 1,
304 | end_line_sel = cur_end.line + 1,
305 | sel_multi = cur_start.line !== cur_end.line,
306 | repl_start = fenceCharsToInsert + "\n",
307 | repl_end = "\n" + fenceCharsToInsert;
308 | if(sel_multi) {
309 | end_line_sel++;
310 | }
311 | // handle last char including \n or not
312 | if(sel_multi && cur_end.ch === 0) {
313 | repl_end = fenceCharsToInsert + "\n";
314 | end_line_sel--;
315 | }
316 | _replaceSelection(cm, false, [repl_start, repl_end]);
317 | cm.setSelection({
318 | line: start_line_sel,
319 | ch: 0
320 | }, {
321 | line: end_line_sel,
322 | ch: 0
323 | });
324 | }
325 |
326 | var cm = editor.codemirror,
327 | cur_start = cm.getCursor("start"),
328 | cur_end = cm.getCursor("end"),
329 | tok = cm.getTokenAt({
330 | line: cur_start.line,
331 | ch: cur_start.ch || 1
332 | }), // avoid ch 0 which is a cursor pos but not token
333 | line = cm.getLineHandle(cur_start.line),
334 | is_code = code_type(cm, cur_start.line, line, tok);
335 | var block_start, block_end, lineCount;
336 |
337 | if(is_code === "single") {
338 | // similar to some SimpleMDE _toggleBlock logic
339 | var start = line.text.slice(0, cur_start.ch).replace("`", ""),
340 | end = line.text.slice(cur_start.ch).replace("`", "");
341 | cm.replaceRange(start + end, {
342 | line: cur_start.line,
343 | ch: 0
344 | }, {
345 | line: cur_start.line,
346 | ch: 99999999999999
347 | });
348 | cur_start.ch--;
349 | if(cur_start !== cur_end) {
350 | cur_end.ch--;
351 | }
352 | cm.setSelection(cur_start, cur_end);
353 | cm.focus();
354 | } else if(is_code === "fenced") {
355 | if(cur_start.line !== cur_end.line || cur_start.ch !== cur_end.ch) {
356 | // use selection
357 |
358 | // find the fenced line so we know what type it is (tilde, backticks, number of them)
359 | for(block_start = cur_start.line; block_start >= 0; block_start--) {
360 | line = cm.getLineHandle(block_start);
361 | if(fencing_line(line)) {
362 | break;
363 | }
364 | }
365 | var fencedTok = cm.getTokenAt({
366 | line: block_start,
367 | ch: 1
368 | });
369 | var fence_chars = token_state(fencedTok).fencedChars;
370 | var start_text, start_line;
371 | var end_text, end_line;
372 | // check for selection going up against fenced lines, in which case we don't want to add more fencing
373 | if(fencing_line(cm.getLineHandle(cur_start.line))) {
374 | start_text = "";
375 | start_line = cur_start.line;
376 | } else if(fencing_line(cm.getLineHandle(cur_start.line - 1))) {
377 | start_text = "";
378 | start_line = cur_start.line - 1;
379 | } else {
380 | start_text = fence_chars + "\n";
381 | start_line = cur_start.line;
382 | }
383 | if(fencing_line(cm.getLineHandle(cur_end.line))) {
384 | end_text = "";
385 | end_line = cur_end.line;
386 | if(cur_end.ch === 0) {
387 | end_line += 1;
388 | }
389 | } else if(cur_end.ch !== 0 && fencing_line(cm.getLineHandle(cur_end.line + 1))) {
390 | end_text = "";
391 | end_line = cur_end.line + 1;
392 | } else {
393 | end_text = fence_chars + "\n";
394 | end_line = cur_end.line + 1;
395 | }
396 | if(cur_end.ch === 0) {
397 | // full last line selected, putting cursor at beginning of next
398 | end_line -= 1;
399 | }
400 | cm.operation(function() {
401 | // end line first, so that line numbers don't change
402 | cm.replaceRange(end_text, {
403 | line: end_line,
404 | ch: 0
405 | }, {
406 | line: end_line + (end_text ? 0 : 1),
407 | ch: 0
408 | });
409 | cm.replaceRange(start_text, {
410 | line: start_line,
411 | ch: 0
412 | }, {
413 | line: start_line + (start_text ? 0 : 1),
414 | ch: 0
415 | });
416 | });
417 | cm.setSelection({
418 | line: start_line + (start_text ? 1 : 0),
419 | ch: 0
420 | }, {
421 | line: end_line + (start_text ? 1 : -1),
422 | ch: 0
423 | });
424 | cm.focus();
425 | } else {
426 | // no selection, search for ends of this fenced block
427 | var search_from = cur_start.line;
428 | if(fencing_line(cm.getLineHandle(cur_start.line))) { // gets a little tricky if cursor is right on a fenced line
429 | if(code_type(cm, cur_start.line + 1) === "fenced") {
430 | block_start = cur_start.line;
431 | search_from = cur_start.line + 1; // for searching for "end"
432 | } else {
433 | block_end = cur_start.line;
434 | search_from = cur_start.line - 1; // for searching for "start"
435 | }
436 | }
437 | if(block_start === undefined) {
438 | for(block_start = search_from; block_start >= 0; block_start--) {
439 | line = cm.getLineHandle(block_start);
440 | if(fencing_line(line)) {
441 | break;
442 | }
443 | }
444 | }
445 | if(block_end === undefined) {
446 | lineCount = cm.lineCount();
447 | for(block_end = search_from; block_end < lineCount; block_end++) {
448 | line = cm.getLineHandle(block_end);
449 | if(fencing_line(line)) {
450 | break;
451 | }
452 | }
453 | }
454 | cm.operation(function() {
455 | cm.replaceRange("", {
456 | line: block_start,
457 | ch: 0
458 | }, {
459 | line: block_start + 1,
460 | ch: 0
461 | });
462 | cm.replaceRange("", {
463 | line: block_end - 1,
464 | ch: 0
465 | }, {
466 | line: block_end,
467 | ch: 0
468 | });
469 | });
470 | cm.focus();
471 | }
472 | } else if(is_code === "indented") {
473 | if(cur_start.line !== cur_end.line || cur_start.ch !== cur_end.ch) {
474 | // use selection
475 | block_start = cur_start.line;
476 | block_end = cur_end.line;
477 | if(cur_end.ch === 0) {
478 | block_end--;
479 | }
480 | } else {
481 | // no selection, search for ends of this indented block
482 | for(block_start = cur_start.line; block_start >= 0; block_start--) {
483 | line = cm.getLineHandle(block_start);
484 | if(line.text.match(/^\s*$/)) {
485 | // empty or all whitespace - keep going
486 | continue;
487 | } else {
488 | if(code_type(cm, block_start, line) !== "indented") {
489 | block_start += 1;
490 | break;
491 | }
492 | }
493 | }
494 | lineCount = cm.lineCount();
495 | for(block_end = cur_start.line; block_end < lineCount; block_end++) {
496 | line = cm.getLineHandle(block_end);
497 | if(line.text.match(/^\s*$/)) {
498 | // empty or all whitespace - keep going
499 | continue;
500 | } else {
501 | if(code_type(cm, block_end, line) !== "indented") {
502 | block_end -= 1;
503 | break;
504 | }
505 | }
506 | }
507 | }
508 | // if we are going to un-indent based on a selected set of lines, and the next line is indented too, we need to
509 | // insert a blank line so that the next line(s) continue to be indented code
510 | var next_line = cm.getLineHandle(block_end + 1),
511 | next_line_last_tok = next_line && cm.getTokenAt({
512 | line: block_end + 1,
513 | ch: next_line.text.length - 1
514 | }),
515 | next_line_indented = next_line_last_tok && token_state(next_line_last_tok).indentedCode;
516 | if(next_line_indented) {
517 | cm.replaceRange("\n", {
518 | line: block_end + 1,
519 | ch: 0
520 | });
521 | }
522 |
523 | for(var i = block_start; i <= block_end; i++) {
524 | cm.indentLine(i, "subtract"); // TODO: this doesn't get tracked in the history, so can't be undone :(
525 | }
526 | cm.focus();
527 | } else {
528 | // insert code formatting
529 | var no_sel_and_starting_of_line = (cur_start.line === cur_end.line && cur_start.ch === cur_end.ch && cur_start.ch === 0);
530 | var sel_multi = cur_start.line !== cur_end.line;
531 | if(no_sel_and_starting_of_line || sel_multi) {
532 | insertFencingAtSelection(cm, cur_start, cur_end, fenceCharsToInsert);
533 | } else {
534 | _replaceSelection(cm, false, ["`", "`"]);
535 | }
536 | }
537 | }
538 |
539 | /**
540 | * Action for toggling blockquote.
541 | */
542 | function toggleBlockquote(editor) {
543 | var cm = editor.codemirror;
544 | _toggleLine(cm, "quote");
545 | }
546 |
547 | /**
548 | * Action for toggling heading size: normal -> h1 -> h2 -> h3 -> h4 -> h5 -> h6 -> normal
549 | */
550 | function toggleHeadingSmaller(editor) {
551 | var cm = editor.codemirror;
552 | _toggleHeading(cm, "smaller");
553 | }
554 |
555 | /**
556 | * Action for toggling heading size: normal -> h6 -> h5 -> h4 -> h3 -> h2 -> h1 -> normal
557 | */
558 | function toggleHeadingBigger(editor) {
559 | var cm = editor.codemirror;
560 | _toggleHeading(cm, "bigger");
561 | }
562 |
563 | /**
564 | * Action for toggling heading size 1
565 | */
566 | function toggleHeading1(editor) {
567 | var cm = editor.codemirror;
568 | _toggleHeading(cm, undefined, 1);
569 | }
570 |
571 | /**
572 | * Action for toggling heading size 2
573 | */
574 | function toggleHeading2(editor) {
575 | var cm = editor.codemirror;
576 | _toggleHeading(cm, undefined, 2);
577 | }
578 |
579 | /**
580 | * Action for toggling heading size 3
581 | */
582 | function toggleHeading3(editor) {
583 | var cm = editor.codemirror;
584 | _toggleHeading(cm, undefined, 3);
585 | }
586 |
587 |
588 | /**
589 | * Action for toggling ul.
590 | */
591 | function toggleUnorderedList(editor) {
592 | var cm = editor.codemirror;
593 | _toggleLine(cm, "unordered-list");
594 | }
595 |
596 |
597 | /**
598 | * Action for toggling ol.
599 | */
600 | function toggleOrderedList(editor) {
601 | var cm = editor.codemirror;
602 | _toggleLine(cm, "ordered-list");
603 | }
604 |
605 | /**
606 | * Action for clean block (remove headline, list, blockquote code, markers)
607 | */
608 | function cleanBlock(editor) {
609 | var cm = editor.codemirror;
610 | _cleanBlock(cm);
611 | }
612 |
613 | /**
614 | * Action for drawing a link.
615 | */
616 | function drawLink(editor) {
617 | var cm = editor.codemirror;
618 | var stat = getState(cm);
619 | var options = editor.options;
620 | var url = "http://";
621 | if(options.promptURLs) {
622 | url = prompt(options.promptTexts.link);
623 | if(!url) {
624 | return false;
625 | }
626 | }
627 | _replaceSelection(cm, stat.link, options.insertTexts.link, url);
628 | }
629 |
630 | /**
631 | * Action for drawing an img.
632 | */
633 | function drawImage(editor) {
634 | var cm = editor.codemirror;
635 | var stat = getState(cm);
636 | var options = editor.options;
637 | var url = "http://";
638 | if(options.promptURLs) {
639 | url = prompt(options.promptTexts.image);
640 | if(!url) {
641 | return false;
642 | }
643 | }
644 | _replaceSelection(cm, stat.image, options.insertTexts.image, url);
645 | }
646 |
647 | /**
648 | * Action for drawing a table.
649 | */
650 | function drawTable(editor) {
651 | var cm = editor.codemirror;
652 | var stat = getState(cm);
653 | var options = editor.options;
654 | _replaceSelection(cm, stat.table, options.insertTexts.table);
655 | }
656 |
657 | /**
658 | * Action for drawing a horizontal rule.
659 | */
660 | function drawHorizontalRule(editor) {
661 | var cm = editor.codemirror;
662 | var stat = getState(cm);
663 | var options = editor.options;
664 | _replaceSelection(cm, stat.image, options.insertTexts.horizontalRule);
665 | }
666 |
667 |
668 | /**
669 | * Undo action.
670 | */
671 | function undo(editor) {
672 | var cm = editor.codemirror;
673 | cm.undo();
674 | cm.focus();
675 | }
676 |
677 |
678 | /**
679 | * Redo action.
680 | */
681 | function redo(editor) {
682 | var cm = editor.codemirror;
683 | cm.redo();
684 | cm.focus();
685 | }
686 |
687 |
688 | /**
689 | * Toggle side by side preview
690 | */
691 | function toggleSideBySide(editor) {
692 | var cm = editor.codemirror;
693 | var wrapper = cm.getWrapperElement();
694 | var preview = wrapper.nextSibling;
695 | var toolbarButton = editor.toolbarElements["side-by-side"];
696 | var useSideBySideListener = false;
697 | if(/editor-preview-active-side/.test(preview.className)) {
698 | preview.className = preview.className.replace(
699 | /\s*editor-preview-active-side\s*/g, ""
700 | );
701 | toolbarButton.className = toolbarButton.className.replace(/\s*active\s*/g, "");
702 | wrapper.className = wrapper.className.replace(/\s*CodeMirror-sided\s*/g, " ");
703 | } else {
704 | // When the preview button is clicked for the first time,
705 | // give some time for the transition from editor.css to fire and the view to slide from right to left,
706 | // instead of just appearing.
707 | setTimeout(function() {
708 | if(!cm.getOption("fullScreen"))
709 | toggleFullScreen(editor);
710 | preview.className += " editor-preview-active-side";
711 | }, 1);
712 | toolbarButton.className += " active";
713 | wrapper.className += " CodeMirror-sided";
714 | useSideBySideListener = true;
715 | }
716 |
717 | // Hide normal preview if active
718 | var previewNormal = wrapper.lastChild;
719 | if(/editor-preview-active/.test(previewNormal.className)) {
720 | previewNormal.className = previewNormal.className.replace(
721 | /\s*editor-preview-active\s*/g, ""
722 | );
723 | var toolbar = editor.toolbarElements.preview;
724 | var toolbar_div = wrapper.previousSibling;
725 | toolbar.className = toolbar.className.replace(/\s*active\s*/g, "");
726 | toolbar_div.className = toolbar_div.className.replace(/\s*disabled-for-preview*/g, "");
727 | }
728 |
729 | var sideBySideRenderingFunction = function() {
730 | preview.innerHTML = editor.options.previewRender(editor.value(), preview);
731 | };
732 |
733 | if(!cm.sideBySideRenderingFunction) {
734 | cm.sideBySideRenderingFunction = sideBySideRenderingFunction;
735 | }
736 |
737 | if(useSideBySideListener) {
738 | preview.innerHTML = editor.options.previewRender(editor.value(), preview);
739 | cm.on("update", cm.sideBySideRenderingFunction);
740 | } else {
741 | cm.off("update", cm.sideBySideRenderingFunction);
742 | }
743 |
744 | // Refresh to fix selection being off (#309)
745 | cm.refresh();
746 | }
747 |
748 |
749 | /**
750 | * Preview action.
751 | */
752 | function togglePreview(editor) {
753 | var cm = editor.codemirror;
754 | var wrapper = cm.getWrapperElement();
755 | var toolbar_div = wrapper.previousSibling;
756 | var toolbar = editor.options.toolbar ? editor.toolbarElements.preview : false;
757 | var preview = wrapper.lastChild;
758 | if(!preview || !/editor-preview/.test(preview.className)) {
759 | preview = document.createElement("div");
760 | preview.className = "editor-preview";
761 | wrapper.appendChild(preview);
762 | }
763 | if(/editor-preview-active/.test(preview.className)) {
764 | preview.className = preview.className.replace(
765 | /\s*editor-preview-active\s*/g, ""
766 | );
767 | if(toolbar) {
768 | toolbar.className = toolbar.className.replace(/\s*active\s*/g, "");
769 | toolbar_div.className = toolbar_div.className.replace(/\s*disabled-for-preview*/g, "");
770 | }
771 | } else {
772 | // When the preview button is clicked for the first time,
773 | // give some time for the transition from editor.css to fire and the view to slide from right to left,
774 | // instead of just appearing.
775 | setTimeout(function() {
776 | preview.className += " editor-preview-active";
777 | }, 1);
778 | if(toolbar) {
779 | toolbar.className += " active";
780 | toolbar_div.className += " disabled-for-preview";
781 | }
782 | }
783 | preview.innerHTML = editor.options.previewRender(editor.value(), preview);
784 |
785 | // Turn off side by side if needed
786 | var sidebyside = cm.getWrapperElement().nextSibling;
787 | if(/editor-preview-active-side/.test(sidebyside.className))
788 | toggleSideBySide(editor);
789 | }
790 |
791 | function _replaceSelection(cm, active, startEnd, url) {
792 | if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
793 | return;
794 |
795 | var text;
796 | var start = startEnd[0];
797 | var end = startEnd[1];
798 | var startPoint = cm.getCursor("start");
799 | var endPoint = cm.getCursor("end");
800 | if(url) {
801 | end = end.replace("#url#", url);
802 | }
803 | if(active) {
804 | text = cm.getLine(startPoint.line);
805 | start = text.slice(0, startPoint.ch);
806 | end = text.slice(startPoint.ch);
807 | cm.replaceRange(start + end, {
808 | line: startPoint.line,
809 | ch: 0
810 | });
811 | } else {
812 | text = cm.getSelection();
813 | cm.replaceSelection(start + text + end);
814 |
815 | startPoint.ch += start.length;
816 | if(startPoint !== endPoint) {
817 | endPoint.ch += start.length;
818 | }
819 | }
820 | cm.setSelection(startPoint, endPoint);
821 | cm.focus();
822 | }
823 |
824 |
825 | function _toggleHeading(cm, direction, size) {
826 | if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
827 | return;
828 |
829 | var startPoint = cm.getCursor("start");
830 | var endPoint = cm.getCursor("end");
831 | for(var i = startPoint.line; i <= endPoint.line; i++) {
832 | (function(i) {
833 | var text = cm.getLine(i);
834 | var currHeadingLevel = text.search(/[^#]/);
835 |
836 | if(direction !== undefined) {
837 | if(currHeadingLevel <= 0) {
838 | if(direction == "bigger") {
839 | text = "###### " + text;
840 | } else {
841 | text = "# " + text;
842 | }
843 | } else if(currHeadingLevel == 6 && direction == "smaller") {
844 | text = text.substr(7);
845 | } else if(currHeadingLevel == 1 && direction == "bigger") {
846 | text = text.substr(2);
847 | } else {
848 | if(direction == "bigger") {
849 | text = text.substr(1);
850 | } else {
851 | text = "#" + text;
852 | }
853 | }
854 | } else {
855 | if(size == 1) {
856 | if(currHeadingLevel <= 0) {
857 | text = "# " + text;
858 | } else if(currHeadingLevel == size) {
859 | text = text.substr(currHeadingLevel + 1);
860 | } else {
861 | text = "# " + text.substr(currHeadingLevel + 1);
862 | }
863 | } else if(size == 2) {
864 | if(currHeadingLevel <= 0) {
865 | text = "## " + text;
866 | } else if(currHeadingLevel == size) {
867 | text = text.substr(currHeadingLevel + 1);
868 | } else {
869 | text = "## " + text.substr(currHeadingLevel + 1);
870 | }
871 | } else {
872 | if(currHeadingLevel <= 0) {
873 | text = "### " + text;
874 | } else if(currHeadingLevel == size) {
875 | text = text.substr(currHeadingLevel + 1);
876 | } else {
877 | text = "### " + text.substr(currHeadingLevel + 1);
878 | }
879 | }
880 | }
881 |
882 | cm.replaceRange(text, {
883 | line: i,
884 | ch: 0
885 | }, {
886 | line: i,
887 | ch: 99999999999999
888 | });
889 | })(i);
890 | }
891 | cm.focus();
892 | }
893 |
894 |
895 | function _toggleLine(cm, name) {
896 | if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
897 | return;
898 |
899 | var stat = getState(cm);
900 | var startPoint = cm.getCursor("start");
901 | var endPoint = cm.getCursor("end");
902 | var repl = {
903 | "quote": /^(\s*)\>\s+/,
904 | "unordered-list": /^(\s*)(\*|\-|\+)\s+/,
905 | "ordered-list": /^(\s*)\d+\.\s+/
906 | };
907 | var map = {
908 | "quote": "> ",
909 | "unordered-list": "* ",
910 | "ordered-list": "1. "
911 | };
912 | for(var i = startPoint.line; i <= endPoint.line; i++) {
913 | (function(i) {
914 | var text = cm.getLine(i);
915 | if(stat[name]) {
916 | text = text.replace(repl[name], "$1");
917 | } else {
918 | text = map[name] + text;
919 | }
920 | cm.replaceRange(text, {
921 | line: i,
922 | ch: 0
923 | }, {
924 | line: i,
925 | ch: 99999999999999
926 | });
927 | })(i);
928 | }
929 | cm.focus();
930 | }
931 |
932 | function _toggleBlock(editor, type, start_chars, end_chars) {
933 | if(/editor-preview-active/.test(editor.codemirror.getWrapperElement().lastChild.className))
934 | return;
935 |
936 | end_chars = (typeof end_chars === "undefined") ? start_chars : end_chars;
937 | var cm = editor.codemirror;
938 | var stat = getState(cm);
939 |
940 | var text;
941 | var start = start_chars;
942 | var end = end_chars;
943 |
944 | var startPoint = cm.getCursor("start");
945 | var endPoint = cm.getCursor("end");
946 |
947 | if(stat[type]) {
948 | text = cm.getLine(startPoint.line);
949 | start = text.slice(0, startPoint.ch);
950 | end = text.slice(startPoint.ch);
951 | if(type == "bold") {
952 | start = start.replace(/(\*\*|__)(?![\s\S]*(\*\*|__))/, "");
953 | end = end.replace(/(\*\*|__)/, "");
954 | } else if(type == "italic") {
955 | start = start.replace(/(\*|_)(?![\s\S]*(\*|_))/, "");
956 | end = end.replace(/(\*|_)/, "");
957 | } else if(type == "strikethrough") {
958 | start = start.replace(/(\*\*|~~)(?![\s\S]*(\*\*|~~))/, "");
959 | end = end.replace(/(\*\*|~~)/, "");
960 | }
961 | cm.replaceRange(start + end, {
962 | line: startPoint.line,
963 | ch: 0
964 | }, {
965 | line: startPoint.line,
966 | ch: 99999999999999
967 | });
968 |
969 | if(type == "bold" || type == "strikethrough") {
970 | startPoint.ch -= 2;
971 | if(startPoint !== endPoint) {
972 | endPoint.ch -= 2;
973 | }
974 | } else if(type == "italic") {
975 | startPoint.ch -= 1;
976 | if(startPoint !== endPoint) {
977 | endPoint.ch -= 1;
978 | }
979 | }
980 | } else {
981 | text = cm.getSelection();
982 | if(type == "bold") {
983 | text = text.split("**").join("");
984 | text = text.split("__").join("");
985 | } else if(type == "italic") {
986 | text = text.split("*").join("");
987 | text = text.split("_").join("");
988 | } else if(type == "strikethrough") {
989 | text = text.split("~~").join("");
990 | }
991 | cm.replaceSelection(start + text + end);
992 |
993 | startPoint.ch += start_chars.length;
994 | endPoint.ch = startPoint.ch + text.length;
995 | }
996 |
997 | cm.setSelection(startPoint, endPoint);
998 | cm.focus();
999 | }
1000 |
1001 | function _cleanBlock(cm) {
1002 | if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
1003 | return;
1004 |
1005 | var startPoint = cm.getCursor("start");
1006 | var endPoint = cm.getCursor("end");
1007 | var text;
1008 |
1009 | for(var line = startPoint.line; line <= endPoint.line; line++) {
1010 | text = cm.getLine(line);
1011 | text = text.replace(/^[ ]*([# ]+|\*|\-|[> ]+|[0-9]+(.|\)))[ ]*/, "");
1012 |
1013 | cm.replaceRange(text, {
1014 | line: line,
1015 | ch: 0
1016 | }, {
1017 | line: line,
1018 | ch: 99999999999999
1019 | });
1020 | }
1021 | }
1022 |
1023 | // Merge the properties of one object into another.
1024 | function _mergeProperties(target, source) {
1025 | for(var property in source) {
1026 | if(source.hasOwnProperty(property)) {
1027 | if(source[property] instanceof Array) {
1028 | target[property] = source[property].concat(target[property] instanceof Array ? target[property] : []);
1029 | } else if(
1030 | source[property] !== null &&
1031 | typeof source[property] === "object" &&
1032 | source[property].constructor === Object
1033 | ) {
1034 | target[property] = _mergeProperties(target[property] || {}, source[property]);
1035 | } else {
1036 | target[property] = source[property];
1037 | }
1038 | }
1039 | }
1040 |
1041 | return target;
1042 | }
1043 |
1044 | // Merge an arbitrary number of objects into one.
1045 | function extend(target) {
1046 | for(var i = 1; i < arguments.length; i++) {
1047 | target = _mergeProperties(target, arguments[i]);
1048 | }
1049 |
1050 | return target;
1051 | }
1052 |
1053 | /* The right word count in respect for CJK. */
1054 | function wordCount(data) {
1055 | var pattern = /[a-zA-Z0-9_\u0392-\u03c9\u0410-\u04F9]+|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/g;
1056 | var m = data.match(pattern);
1057 | var count = 0;
1058 | if(m === null) return count;
1059 | for(var i = 0; i < m.length; i++) {
1060 | if(m[i].charCodeAt(0) >= 0x4E00) {
1061 | count += m[i].length;
1062 | } else {
1063 | count += 1;
1064 | }
1065 | }
1066 | return count;
1067 | }
1068 |
1069 | var toolbarBuiltInButtons = {
1070 | "bold": {
1071 | name: "bold",
1072 | action: toggleBold,
1073 | className: "fa fa-bold",
1074 | title: "Bold",
1075 | default: true
1076 | },
1077 | "italic": {
1078 | name: "italic",
1079 | action: toggleItalic,
1080 | className: "fa fa-italic",
1081 | title: "Italic",
1082 | default: true
1083 | },
1084 | "strikethrough": {
1085 | name: "strikethrough",
1086 | action: toggleStrikethrough,
1087 | className: "fa fa-strikethrough",
1088 | title: "Strikethrough"
1089 | },
1090 | "heading": {
1091 | name: "heading",
1092 | action: toggleHeadingSmaller,
1093 | className: "fa fa-header",
1094 | title: "Heading",
1095 | default: true
1096 | },
1097 | "heading-smaller": {
1098 | name: "heading-smaller",
1099 | action: toggleHeadingSmaller,
1100 | className: "fa fa-header fa-header-x fa-header-smaller",
1101 | title: "Smaller Heading"
1102 | },
1103 | "heading-bigger": {
1104 | name: "heading-bigger",
1105 | action: toggleHeadingBigger,
1106 | className: "fa fa-header fa-header-x fa-header-bigger",
1107 | title: "Bigger Heading"
1108 | },
1109 | "heading-1": {
1110 | name: "heading-1",
1111 | action: toggleHeading1,
1112 | className: "fa fa-header fa-header-x fa-header-1",
1113 | title: "Big Heading"
1114 | },
1115 | "heading-2": {
1116 | name: "heading-2",
1117 | action: toggleHeading2,
1118 | className: "fa fa-header fa-header-x fa-header-2",
1119 | title: "Medium Heading"
1120 | },
1121 | "heading-3": {
1122 | name: "heading-3",
1123 | action: toggleHeading3,
1124 | className: "fa fa-header fa-header-x fa-header-3",
1125 | title: "Small Heading"
1126 | },
1127 | "separator-1": {
1128 | name: "separator-1"
1129 | },
1130 | "code": {
1131 | name: "code",
1132 | action: toggleCodeBlock,
1133 | className: "fa fa-code",
1134 | title: "Code"
1135 | },
1136 | "quote": {
1137 | name: "quote",
1138 | action: toggleBlockquote,
1139 | className: "fa fa-quote-left",
1140 | title: "Quote",
1141 | default: true
1142 | },
1143 | "unordered-list": {
1144 | name: "unordered-list",
1145 | action: toggleUnorderedList,
1146 | className: "fa fa-list-ul",
1147 | title: "Generic List",
1148 | default: true
1149 | },
1150 | "ordered-list": {
1151 | name: "ordered-list",
1152 | action: toggleOrderedList,
1153 | className: "fa fa-list-ol",
1154 | title: "Numbered List",
1155 | default: true
1156 | },
1157 | "clean-block": {
1158 | name: "clean-block",
1159 | action: cleanBlock,
1160 | className: "fa fa-eraser fa-clean-block",
1161 | title: "Clean block"
1162 | },
1163 | "separator-2": {
1164 | name: "separator-2"
1165 | },
1166 | "link": {
1167 | name: "link",
1168 | action: drawLink,
1169 | className: "fa fa-link",
1170 | title: "Create Link",
1171 | default: true
1172 | },
1173 | "image": {
1174 | name: "image",
1175 | action: drawImage,
1176 | className: "fa fa-picture-o",
1177 | title: "Insert Image",
1178 | default: true
1179 | },
1180 | "table": {
1181 | name: "table",
1182 | action: drawTable,
1183 | className: "fa fa-table",
1184 | title: "Insert Table"
1185 | },
1186 | "horizontal-rule": {
1187 | name: "horizontal-rule",
1188 | action: drawHorizontalRule,
1189 | className: "fa fa-minus",
1190 | title: "Insert Horizontal Line"
1191 | },
1192 | "separator-3": {
1193 | name: "separator-3"
1194 | },
1195 | "preview": {
1196 | name: "preview",
1197 | action: togglePreview,
1198 | className: "fa fa-eye no-disable",
1199 | title: "Toggle Preview",
1200 | default: true
1201 | },
1202 | "side-by-side": {
1203 | name: "side-by-side",
1204 | action: toggleSideBySide,
1205 | className: "fa fa-columns no-disable no-mobile",
1206 | title: "Toggle Side by Side",
1207 | default: true
1208 | },
1209 | "fullscreen": {
1210 | name: "fullscreen",
1211 | action: toggleFullScreen,
1212 | className: "fa fa-arrows-alt no-disable no-mobile",
1213 | title: "Toggle Fullscreen",
1214 | default: true
1215 | },
1216 | "separator-4": {
1217 | name: "separator-4"
1218 | },
1219 | "guide": {
1220 | name: "guide",
1221 | action: "https://simplemde.com/markdown-guide",
1222 | className: "fa fa-question-circle",
1223 | title: "Markdown Guide",
1224 | default: true
1225 | },
1226 | "separator-5": {
1227 | name: "separator-5"
1228 | },
1229 | "undo": {
1230 | name: "undo",
1231 | action: undo,
1232 | className: "fa fa-undo no-disable",
1233 | title: "Undo"
1234 | },
1235 | "redo": {
1236 | name: "redo",
1237 | action: redo,
1238 | className: "fa fa-repeat no-disable",
1239 | title: "Redo"
1240 | }
1241 | };
1242 |
1243 | var insertTexts = {
1244 | link: ["[", "](#url#)"],
1245 | image: [""],
1246 | table: ["", "\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n"],
1247 | horizontalRule: ["", "\n\n-----\n\n"]
1248 | };
1249 |
1250 | var promptTexts = {
1251 | link: "URL for the link:",
1252 | image: "URL of the image:"
1253 | };
1254 |
1255 | var blockStyles = {
1256 | "bold": "**",
1257 | "code": "```",
1258 | "italic": "*"
1259 | };
1260 |
1261 | /**
1262 | * Interface of SimpleMDE.
1263 | */
1264 | function SimpleMDE(options) {
1265 | // Handle options parameter
1266 | options = options || {};
1267 |
1268 |
1269 | // Used later to refer to it"s parent
1270 | options.parent = this;
1271 |
1272 |
1273 | // Check if Font Awesome needs to be auto downloaded
1274 | var autoDownloadFA = true;
1275 |
1276 | if(options.autoDownloadFontAwesome === false) {
1277 | autoDownloadFA = false;
1278 | }
1279 |
1280 | if(options.autoDownloadFontAwesome !== true) {
1281 | var styleSheets = document.styleSheets;
1282 | for(var i = 0; i < styleSheets.length; i++) {
1283 | if(!styleSheets[i].href)
1284 | continue;
1285 |
1286 | if(styleSheets[i].href.indexOf("//maxcdn.bootstrapcdn.com/font-awesome/") > -1) {
1287 | autoDownloadFA = false;
1288 | }
1289 | }
1290 | }
1291 |
1292 | if(autoDownloadFA) {
1293 | var link = document.createElement("link");
1294 | link.rel = "stylesheet";
1295 | link.href = "https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css";
1296 | document.getElementsByTagName("head")[0].appendChild(link);
1297 | }
1298 |
1299 |
1300 | // Find the textarea to use
1301 | if(options.element) {
1302 | this.element = options.element;
1303 | } else if(options.element === null) {
1304 | // This means that the element option was specified, but no element was found
1305 | console.log("SimpleMDE: Error. No element was found.");
1306 | return;
1307 | }
1308 |
1309 |
1310 | // Handle toolbar
1311 | if(options.toolbar === undefined) {
1312 | // Initialize
1313 | options.toolbar = [];
1314 |
1315 |
1316 | // Loop over the built in buttons, to get the preferred order
1317 | for(var key in toolbarBuiltInButtons) {
1318 | if(toolbarBuiltInButtons.hasOwnProperty(key)) {
1319 | if(key.indexOf("separator-") != -1) {
1320 | options.toolbar.push("|");
1321 | }
1322 |
1323 | if(toolbarBuiltInButtons[key].default === true || (options.showIcons && options.showIcons.constructor === Array && options.showIcons.indexOf(key) != -1)) {
1324 | options.toolbar.push(key);
1325 | }
1326 | }
1327 | }
1328 | }
1329 |
1330 |
1331 | // Handle status bar
1332 | if(!options.hasOwnProperty("status")) {
1333 | options.status = ["autosave", "lines", "words", "cursor"];
1334 | }
1335 |
1336 |
1337 | // Add default preview rendering function
1338 | if(!options.previewRender) {
1339 | options.previewRender = function(plainText) {
1340 | // Note: "this" refers to the options object
1341 | return this.parent.markdown(plainText);
1342 | };
1343 | }
1344 |
1345 |
1346 | // Set default options for parsing config
1347 | options.parsingConfig = extend({
1348 | highlightFormatting: true // needed for toggleCodeBlock to detect types of code
1349 | }, options.parsingConfig || {});
1350 |
1351 |
1352 | // Merging the insertTexts, with the given options
1353 | options.insertTexts = extend({}, insertTexts, options.insertTexts || {});
1354 |
1355 |
1356 | // Merging the promptTexts, with the given options
1357 | options.promptTexts = promptTexts;
1358 |
1359 |
1360 | // Merging the blockStyles, with the given options
1361 | options.blockStyles = extend({}, blockStyles, options.blockStyles || {});
1362 |
1363 |
1364 | // Merging the shortcuts, with the given options
1365 | options.shortcuts = extend({}, shortcuts, options.shortcuts || {});
1366 |
1367 |
1368 | // Change unique_id to uniqueId for backwards compatibility
1369 | if(options.autosave != undefined && options.autosave.unique_id != undefined && options.autosave.unique_id != "")
1370 | options.autosave.uniqueId = options.autosave.unique_id;
1371 |
1372 |
1373 | // Update this options
1374 | this.options = options;
1375 |
1376 |
1377 | // Auto render
1378 | this.render();
1379 |
1380 |
1381 | // The codemirror component is only available after rendering
1382 | // so, the setter for the initialValue can only run after
1383 | // the element has been rendered
1384 | if(options.initialValue && (!this.options.autosave || this.options.autosave.foundSavedValue !== true)) {
1385 | this.value(options.initialValue);
1386 | }
1387 | }
1388 |
1389 | /**
1390 | * Default markdown render.
1391 | */
1392 | SimpleMDE.prototype.markdown = function(text) {
1393 | if(marked) {
1394 | // Initialize
1395 | var markedOptions = {};
1396 |
1397 |
1398 | // Update options
1399 | if(this.options && this.options.renderingConfig && this.options.renderingConfig.singleLineBreaks === false) {
1400 | markedOptions.breaks = false;
1401 | } else {
1402 | markedOptions.breaks = true;
1403 | }
1404 |
1405 | if(this.options && this.options.renderingConfig && this.options.renderingConfig.codeSyntaxHighlighting === true && window.hljs) {
1406 | markedOptions.highlight = function(code) {
1407 | return window.hljs.highlightAuto(code).value;
1408 | };
1409 | }
1410 |
1411 |
1412 | // Set options
1413 | marked.setOptions(markedOptions);
1414 |
1415 |
1416 | // Return
1417 | return marked(text);
1418 | }
1419 | };
1420 |
1421 | /**
1422 | * Render editor to the given element.
1423 | */
1424 | SimpleMDE.prototype.render = function(el) {
1425 | if(!el) {
1426 | el = this.element || document.getElementsByTagName("textarea")[0];
1427 | }
1428 |
1429 | if(this._rendered && this._rendered === el) {
1430 | // Already rendered.
1431 | return;
1432 | }
1433 |
1434 | this.element = el;
1435 | var options = this.options;
1436 |
1437 | var self = this;
1438 | var keyMaps = {};
1439 |
1440 | for(var key in options.shortcuts) {
1441 | // null stands for "do not bind this command"
1442 | if(options.shortcuts[key] !== null && bindings[key] !== null) {
1443 | (function(key) {
1444 | keyMaps[fixShortcut(options.shortcuts[key])] = function() {
1445 | bindings[key](self);
1446 | };
1447 | })(key);
1448 | }
1449 | }
1450 |
1451 | keyMaps["Enter"] = "newlineAndIndentContinueMarkdownList";
1452 | keyMaps["Tab"] = "tabAndIndentMarkdownList";
1453 | keyMaps["Shift-Tab"] = "shiftTabAndUnindentMarkdownList";
1454 | keyMaps["Esc"] = function(cm) {
1455 | if(cm.getOption("fullScreen")) toggleFullScreen(self);
1456 | };
1457 |
1458 | document.addEventListener("keydown", function(e) {
1459 | e = e || window.event;
1460 |
1461 | if(e.keyCode == 27) {
1462 | if(self.codemirror.getOption("fullScreen")) toggleFullScreen(self);
1463 | }
1464 | }, false);
1465 |
1466 | var mode, backdrop;
1467 | if(options.spellChecker !== false) {
1468 | mode = "spell-checker";
1469 | backdrop = options.parsingConfig;
1470 | backdrop.name = "gfm";
1471 | backdrop.gitHubSpice = false;
1472 |
1473 | CodeMirrorSpellChecker({
1474 | codeMirrorInstance: CodeMirror
1475 | });
1476 | } else {
1477 | mode = options.parsingConfig;
1478 | mode.name = "gfm";
1479 | mode.gitHubSpice = false;
1480 | }
1481 |
1482 | this.codemirror = CodeMirror.fromTextArea(el, {
1483 | mode: mode,
1484 | backdrop: backdrop,
1485 | theme: "paper",
1486 | tabSize: (options.tabSize != undefined) ? options.tabSize : 2,
1487 | indentUnit: (options.tabSize != undefined) ? options.tabSize : 2,
1488 | indentWithTabs: (options.indentWithTabs === false) ? false : true,
1489 | lineNumbers: false,
1490 | autofocus: (options.autofocus === true) ? true : false,
1491 | extraKeys: keyMaps,
1492 | lineWrapping: (options.lineWrapping === false) ? false : true,
1493 | allowDropFileTypes: ["text/plain"],
1494 | placeholder: options.placeholder || el.getAttribute("placeholder") || "",
1495 | styleSelectedText: (options.styleSelectedText != undefined) ? options.styleSelectedText : true
1496 | });
1497 |
1498 | if(options.forceSync === true) {
1499 | var cm = this.codemirror;
1500 | cm.on("change", function() {
1501 | cm.save();
1502 | });
1503 | }
1504 |
1505 | this.gui = {};
1506 |
1507 | if(options.toolbar !== false) {
1508 | this.gui.toolbar = this.createToolbar();
1509 | }
1510 | if(options.status !== false) {
1511 | this.gui.statusbar = this.createStatusbar();
1512 | }
1513 | if(options.autosave != undefined && options.autosave.enabled === true) {
1514 | this.autosave();
1515 | }
1516 |
1517 | this.gui.sideBySide = this.createSideBySide();
1518 |
1519 | this._rendered = this.element;
1520 |
1521 |
1522 | // Fixes CodeMirror bug (#344)
1523 | var temp_cm = this.codemirror;
1524 | setTimeout(function() {
1525 | temp_cm.refresh();
1526 | }.bind(temp_cm), 0);
1527 | };
1528 |
1529 | // 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.
1530 | function isLocalStorageAvailable() {
1531 | if(typeof localStorage === "object") {
1532 | try {
1533 | localStorage.setItem("smde_localStorage", 1);
1534 | localStorage.removeItem("smde_localStorage");
1535 | } catch(e) {
1536 | return false;
1537 | }
1538 | } else {
1539 | return false;
1540 | }
1541 |
1542 | return true;
1543 | }
1544 |
1545 | SimpleMDE.prototype.autosave = function() {
1546 | if(isLocalStorageAvailable()) {
1547 | var simplemde = this;
1548 |
1549 | if(this.options.autosave.uniqueId == undefined || this.options.autosave.uniqueId == "") {
1550 | console.log("SimpleMDE: You must set a uniqueId to use the autosave feature");
1551 | return;
1552 | }
1553 |
1554 | if(simplemde.element.form != null && simplemde.element.form != undefined) {
1555 | simplemde.element.form.addEventListener("submit", function() {
1556 | localStorage.removeItem("smde_" + simplemde.options.autosave.uniqueId);
1557 | });
1558 | }
1559 |
1560 | if(this.options.autosave.loaded !== true) {
1561 | if(typeof localStorage.getItem("smde_" + this.options.autosave.uniqueId) == "string" && localStorage.getItem("smde_" + this.options.autosave.uniqueId) != "") {
1562 | this.codemirror.setValue(localStorage.getItem("smde_" + this.options.autosave.uniqueId));
1563 | this.options.autosave.foundSavedValue = true;
1564 | }
1565 |
1566 | this.options.autosave.loaded = true;
1567 | }
1568 |
1569 | localStorage.setItem("smde_" + this.options.autosave.uniqueId, simplemde.value());
1570 |
1571 | var el = document.getElementById("autosaved");
1572 | if(el != null && el != undefined && el != "") {
1573 | var d = new Date();
1574 | var hh = d.getHours();
1575 | var m = d.getMinutes();
1576 | var dd = "am";
1577 | var h = hh;
1578 | if(h >= 12) {
1579 | h = hh - 12;
1580 | dd = "pm";
1581 | }
1582 | if(h == 0) {
1583 | h = 12;
1584 | }
1585 | m = m < 10 ? "0" + m : m;
1586 |
1587 | el.innerHTML = "Autosaved: " + h + ":" + m + " " + dd;
1588 | }
1589 |
1590 | this.autosaveTimeoutId = setTimeout(function() {
1591 | simplemde.autosave();
1592 | }, this.options.autosave.delay || 10000);
1593 | } else {
1594 | console.log("SimpleMDE: localStorage not available, cannot autosave");
1595 | }
1596 | };
1597 |
1598 | SimpleMDE.prototype.clearAutosavedValue = function() {
1599 | if(isLocalStorageAvailable()) {
1600 | if(this.options.autosave == undefined || this.options.autosave.uniqueId == undefined || this.options.autosave.uniqueId == "") {
1601 | console.log("SimpleMDE: You must set a uniqueId to clear the autosave value");
1602 | return;
1603 | }
1604 |
1605 | localStorage.removeItem("smde_" + this.options.autosave.uniqueId);
1606 | } else {
1607 | console.log("SimpleMDE: localStorage not available, cannot autosave");
1608 | }
1609 | };
1610 |
1611 | SimpleMDE.prototype.createSideBySide = function() {
1612 | var cm = this.codemirror;
1613 | var wrapper = cm.getWrapperElement();
1614 | var preview = wrapper.nextSibling;
1615 |
1616 | if(!preview || !/editor-preview-side/.test(preview.className)) {
1617 | preview = document.createElement("div");
1618 | preview.className = "editor-preview-side";
1619 | wrapper.parentNode.insertBefore(preview, wrapper.nextSibling);
1620 | }
1621 |
1622 | // Syncs scroll editor -> preview
1623 | var cScroll = false;
1624 | var pScroll = false;
1625 | cm.on("scroll", function(v) {
1626 | if(cScroll) {
1627 | cScroll = false;
1628 | return;
1629 | }
1630 | pScroll = true;
1631 | var height = v.getScrollInfo().height - v.getScrollInfo().clientHeight;
1632 | var ratio = parseFloat(v.getScrollInfo().top) / height;
1633 | var move = (preview.scrollHeight - preview.clientHeight) * ratio;
1634 | preview.scrollTop = move;
1635 | });
1636 |
1637 | // Syncs scroll preview -> editor
1638 | preview.onscroll = function() {
1639 | if(pScroll) {
1640 | pScroll = false;
1641 | return;
1642 | }
1643 | cScroll = true;
1644 | var height = preview.scrollHeight - preview.clientHeight;
1645 | var ratio = parseFloat(preview.scrollTop) / height;
1646 | var move = (cm.getScrollInfo().height - cm.getScrollInfo().clientHeight) * ratio;
1647 | cm.scrollTo(0, move);
1648 | };
1649 | return preview;
1650 | };
1651 |
1652 | SimpleMDE.prototype.createToolbar = function(items) {
1653 | items = items || this.options.toolbar;
1654 |
1655 | if(!items || items.length === 0) {
1656 | return;
1657 | }
1658 | var i;
1659 | for(i = 0; i < items.length; i++) {
1660 | if(toolbarBuiltInButtons[items[i]] != undefined) {
1661 | items[i] = toolbarBuiltInButtons[items[i]];
1662 | }
1663 | }
1664 |
1665 | var bar = document.createElement("div");
1666 | bar.className = "editor-toolbar";
1667 |
1668 | var self = this;
1669 |
1670 | var toolbarData = {};
1671 | self.toolbar = items;
1672 |
1673 | for(i = 0; i < items.length; i++) {
1674 | if(items[i].name == "guide" && self.options.toolbarGuideIcon === false)
1675 | continue;
1676 |
1677 | if(self.options.hideIcons && self.options.hideIcons.indexOf(items[i].name) != -1)
1678 | continue;
1679 |
1680 | // Fullscreen does not work well on mobile devices (even tablets)
1681 | // In the future, hopefully this can be resolved
1682 | if((items[i].name == "fullscreen" || items[i].name == "side-by-side") && isMobile())
1683 | continue;
1684 |
1685 |
1686 | // Don't include trailing separators
1687 | if(items[i] === "|") {
1688 | var nonSeparatorIconsFollow = false;
1689 |
1690 | for(var x = (i + 1); x < items.length; x++) {
1691 | if(items[x] !== "|" && (!self.options.hideIcons || self.options.hideIcons.indexOf(items[x].name) == -1)) {
1692 | nonSeparatorIconsFollow = true;
1693 | }
1694 | }
1695 |
1696 | if(!nonSeparatorIconsFollow)
1697 | continue;
1698 | }
1699 |
1700 |
1701 | // Create the icon and append to the toolbar
1702 | (function(item) {
1703 | var el;
1704 | if(item === "|") {
1705 | el = createSep();
1706 | } else {
1707 | el = createIcon(item, self.options.toolbarTips, self.options.shortcuts);
1708 | }
1709 |
1710 | // bind events, special for info
1711 | if(item.action) {
1712 | if(typeof item.action === "function") {
1713 | el.onclick = function(e) {
1714 | e.preventDefault();
1715 | item.action(self);
1716 | };
1717 | } else if(typeof item.action === "string") {
1718 | el.href = item.action;
1719 | el.target = "_blank";
1720 | }
1721 | }
1722 |
1723 | toolbarData[item.name || item] = el;
1724 | bar.appendChild(el);
1725 | })(items[i]);
1726 | }
1727 |
1728 | self.toolbarElements = toolbarData;
1729 |
1730 | var cm = this.codemirror;
1731 | cm.on("cursorActivity", function() {
1732 | var stat = getState(cm);
1733 |
1734 | for(var key in toolbarData) {
1735 | (function(key) {
1736 | var el = toolbarData[key];
1737 | if(stat[key]) {
1738 | el.className += " active";
1739 | } else if(key != "fullscreen" && key != "side-by-side") {
1740 | el.className = el.className.replace(/\s*active\s*/g, "");
1741 | }
1742 | })(key);
1743 | }
1744 | });
1745 |
1746 | var cmWrapper = cm.getWrapperElement();
1747 | cmWrapper.parentNode.insertBefore(bar, cmWrapper);
1748 | return bar;
1749 | };
1750 |
1751 | SimpleMDE.prototype.createStatusbar = function(status) {
1752 | // Initialize
1753 | status = status || this.options.status;
1754 | var options = this.options;
1755 | var cm = this.codemirror;
1756 |
1757 |
1758 | // Make sure the status variable is valid
1759 | if(!status || status.length === 0)
1760 | return;
1761 |
1762 |
1763 | // Set up the built-in items
1764 | var items = [];
1765 | var i, onUpdate, defaultValue;
1766 |
1767 | for(i = 0; i < status.length; i++) {
1768 | // Reset some values
1769 | onUpdate = undefined;
1770 | defaultValue = undefined;
1771 |
1772 |
1773 | // Handle if custom or not
1774 | if(typeof status[i] === "object") {
1775 | items.push({
1776 | className: status[i].className,
1777 | defaultValue: status[i].defaultValue,
1778 | onUpdate: status[i].onUpdate
1779 | });
1780 | } else {
1781 | var name = status[i];
1782 |
1783 | if(name === "words") {
1784 | defaultValue = function(el) {
1785 | el.innerHTML = wordCount(cm.getValue());
1786 | };
1787 | onUpdate = function(el) {
1788 | el.innerHTML = wordCount(cm.getValue());
1789 | };
1790 | } else if(name === "lines") {
1791 | defaultValue = function(el) {
1792 | el.innerHTML = cm.lineCount();
1793 | };
1794 | onUpdate = function(el) {
1795 | el.innerHTML = cm.lineCount();
1796 | };
1797 | } else if(name === "cursor") {
1798 | defaultValue = function(el) {
1799 | el.innerHTML = "0:0";
1800 | };
1801 | onUpdate = function(el) {
1802 | var pos = cm.getCursor();
1803 | el.innerHTML = pos.line + ":" + pos.ch;
1804 | };
1805 | } else if(name === "autosave") {
1806 | defaultValue = function(el) {
1807 | if(options.autosave != undefined && options.autosave.enabled === true) {
1808 | el.setAttribute("id", "autosaved");
1809 | }
1810 | };
1811 | }
1812 |
1813 | items.push({
1814 | className: name,
1815 | defaultValue: defaultValue,
1816 | onUpdate: onUpdate
1817 | });
1818 | }
1819 | }
1820 |
1821 |
1822 | // Create element for the status bar
1823 | var bar = document.createElement("div");
1824 | bar.className = "editor-statusbar";
1825 |
1826 |
1827 | // Create a new span for each item
1828 | for(i = 0; i < items.length; i++) {
1829 | // Store in temporary variable
1830 | var item = items[i];
1831 |
1832 |
1833 | // Create span element
1834 | var el = document.createElement("span");
1835 | el.className = item.className;
1836 |
1837 |
1838 | // Ensure the defaultValue is a function
1839 | if(typeof item.defaultValue === "function") {
1840 | item.defaultValue(el);
1841 | }
1842 |
1843 |
1844 | // Ensure the onUpdate is a function
1845 | if(typeof item.onUpdate === "function") {
1846 | // Create a closure around the span of the current action, then execute the onUpdate handler
1847 | this.codemirror.on("update", (function(el, item) {
1848 | return function() {
1849 | item.onUpdate(el);
1850 | };
1851 | }(el, item)));
1852 | }
1853 |
1854 |
1855 | // Append the item to the status bar
1856 | bar.appendChild(el);
1857 | }
1858 |
1859 |
1860 | // Insert the status bar into the DOM
1861 | var cmWrapper = this.codemirror.getWrapperElement();
1862 | cmWrapper.parentNode.insertBefore(bar, cmWrapper.nextSibling);
1863 | return bar;
1864 | };
1865 |
1866 | /**
1867 | * Get or set the text content.
1868 | */
1869 | SimpleMDE.prototype.value = function(val) {
1870 | if(val === undefined) {
1871 | return this.codemirror.getValue();
1872 | } else {
1873 | this.codemirror.getDoc().setValue(val);
1874 | return this;
1875 | }
1876 | };
1877 |
1878 |
1879 | /**
1880 | * Bind static methods for exports.
1881 | */
1882 | SimpleMDE.toggleBold = toggleBold;
1883 | SimpleMDE.toggleItalic = toggleItalic;
1884 | SimpleMDE.toggleStrikethrough = toggleStrikethrough;
1885 | SimpleMDE.toggleBlockquote = toggleBlockquote;
1886 | SimpleMDE.toggleHeadingSmaller = toggleHeadingSmaller;
1887 | SimpleMDE.toggleHeadingBigger = toggleHeadingBigger;
1888 | SimpleMDE.toggleHeading1 = toggleHeading1;
1889 | SimpleMDE.toggleHeading2 = toggleHeading2;
1890 | SimpleMDE.toggleHeading3 = toggleHeading3;
1891 | SimpleMDE.toggleCodeBlock = toggleCodeBlock;
1892 | SimpleMDE.toggleUnorderedList = toggleUnorderedList;
1893 | SimpleMDE.toggleOrderedList = toggleOrderedList;
1894 | SimpleMDE.cleanBlock = cleanBlock;
1895 | SimpleMDE.drawLink = drawLink;
1896 | SimpleMDE.drawImage = drawImage;
1897 | SimpleMDE.drawTable = drawTable;
1898 | SimpleMDE.drawHorizontalRule = drawHorizontalRule;
1899 | SimpleMDE.undo = undo;
1900 | SimpleMDE.redo = redo;
1901 | SimpleMDE.togglePreview = togglePreview;
1902 | SimpleMDE.toggleSideBySide = toggleSideBySide;
1903 | SimpleMDE.toggleFullScreen = toggleFullScreen;
1904 |
1905 | /**
1906 | * Bind instance methods for exports.
1907 | */
1908 | SimpleMDE.prototype.toggleBold = function() {
1909 | toggleBold(this);
1910 | };
1911 | SimpleMDE.prototype.toggleItalic = function() {
1912 | toggleItalic(this);
1913 | };
1914 | SimpleMDE.prototype.toggleStrikethrough = function() {
1915 | toggleStrikethrough(this);
1916 | };
1917 | SimpleMDE.prototype.toggleBlockquote = function() {
1918 | toggleBlockquote(this);
1919 | };
1920 | SimpleMDE.prototype.toggleHeadingSmaller = function() {
1921 | toggleHeadingSmaller(this);
1922 | };
1923 | SimpleMDE.prototype.toggleHeadingBigger = function() {
1924 | toggleHeadingBigger(this);
1925 | };
1926 | SimpleMDE.prototype.toggleHeading1 = function() {
1927 | toggleHeading1(this);
1928 | };
1929 | SimpleMDE.prototype.toggleHeading2 = function() {
1930 | toggleHeading2(this);
1931 | };
1932 | SimpleMDE.prototype.toggleHeading3 = function() {
1933 | toggleHeading3(this);
1934 | };
1935 | SimpleMDE.prototype.toggleCodeBlock = function() {
1936 | toggleCodeBlock(this);
1937 | };
1938 | SimpleMDE.prototype.toggleUnorderedList = function() {
1939 | toggleUnorderedList(this);
1940 | };
1941 | SimpleMDE.prototype.toggleOrderedList = function() {
1942 | toggleOrderedList(this);
1943 | };
1944 | SimpleMDE.prototype.cleanBlock = function() {
1945 | cleanBlock(this);
1946 | };
1947 | SimpleMDE.prototype.drawLink = function() {
1948 | drawLink(this);
1949 | };
1950 | SimpleMDE.prototype.drawImage = function() {
1951 | drawImage(this);
1952 | };
1953 | SimpleMDE.prototype.drawTable = function() {
1954 | drawTable(this);
1955 | };
1956 | SimpleMDE.prototype.drawHorizontalRule = function() {
1957 | drawHorizontalRule(this);
1958 | };
1959 | SimpleMDE.prototype.undo = function() {
1960 | undo(this);
1961 | };
1962 | SimpleMDE.prototype.redo = function() {
1963 | redo(this);
1964 | };
1965 | SimpleMDE.prototype.togglePreview = function() {
1966 | togglePreview(this);
1967 | };
1968 | SimpleMDE.prototype.toggleSideBySide = function() {
1969 | toggleSideBySide(this);
1970 | };
1971 | SimpleMDE.prototype.toggleFullScreen = function() {
1972 | toggleFullScreen(this);
1973 | };
1974 |
1975 | SimpleMDE.prototype.isPreviewActive = function() {
1976 | var cm = this.codemirror;
1977 | var wrapper = cm.getWrapperElement();
1978 | var preview = wrapper.lastChild;
1979 |
1980 | return /editor-preview-active/.test(preview.className);
1981 | };
1982 |
1983 | SimpleMDE.prototype.isSideBySideActive = function() {
1984 | var cm = this.codemirror;
1985 | var wrapper = cm.getWrapperElement();
1986 | var preview = wrapper.nextSibling;
1987 |
1988 | return /editor-preview-active-side/.test(preview.className);
1989 | };
1990 |
1991 | SimpleMDE.prototype.isFullscreenActive = function() {
1992 | var cm = this.codemirror;
1993 |
1994 | return cm.getOption("fullScreen");
1995 | };
1996 |
1997 | SimpleMDE.prototype.getState = function() {
1998 | var cm = this.codemirror;
1999 |
2000 | return getState(cm);
2001 | };
2002 |
2003 | SimpleMDE.prototype.toTextArea = function() {
2004 | var cm = this.codemirror;
2005 | var wrapper = cm.getWrapperElement();
2006 |
2007 | if(wrapper.parentNode) {
2008 | if(this.gui.toolbar) {
2009 | wrapper.parentNode.removeChild(this.gui.toolbar);
2010 | }
2011 | if(this.gui.statusbar) {
2012 | wrapper.parentNode.removeChild(this.gui.statusbar);
2013 | }
2014 | if(this.gui.sideBySide) {
2015 | wrapper.parentNode.removeChild(this.gui.sideBySide);
2016 | }
2017 | }
2018 |
2019 | cm.toTextArea();
2020 |
2021 | if(this.autosaveTimeoutId) {
2022 | clearTimeout(this.autosaveTimeoutId);
2023 | this.autosaveTimeoutId = undefined;
2024 | this.clearAutosavedValue();
2025 | }
2026 | };
2027 |
2028 | module.exports = SimpleMDE;
--------------------------------------------------------------------------------