2015-10-07 22:52:14 +02:00
/*global require,module*/
"use strict" ;
var CodeMirror = require ( "codemirror" ) ;
require ( "codemirror/addon/edit/continuelist.js" ) ;
2015-10-15 12:01:16 +02:00
require ( "./codemirror/tablist" ) ;
2015-10-07 22:52:14 +02:00
require ( "codemirror/addon/display/fullscreen.js" ) ;
require ( "codemirror/mode/markdown/markdown.js" ) ;
require ( "codemirror/addon/mode/overlay.js" ) ;
2015-12-09 00:06:38 +01:00
require ( "codemirror/addon/display/placeholder.js" ) ;
2016-03-25 16:56:44 +01:00
require ( "codemirror/addon/selection/mark-selection.js" ) ;
2015-10-15 12:01:16 +02:00
require ( "codemirror/mode/gfm/gfm.js" ) ;
2015-10-07 22:52:14 +02:00
require ( "codemirror/mode/xml/xml.js" ) ;
2016-06-08 04:27:53 +02:00
var CodeMirrorSpellChecker = require ( "codemirror-spell-checker" ) ;
2015-10-15 12:01:16 +02:00
var marked = require ( "marked" ) ;
2015-10-07 22:52:14 +02:00
2015-11-04 05:01:40 +01:00
// Some variables
2015-06-19 22:37:06 +02:00
var isMac = /Mac/ . test ( navigator . platform ) ;
2016-01-09 10:13:16 +01:00
// Mapping of actions that can be bound to keyboard shortcuts or toolbar buttons
2016-01-07 10:38:19 +01:00
var bindings = {
"toggleBold" : toggleBold ,
"toggleItalic" : toggleItalic ,
"drawLink" : drawLink ,
"toggleHeadingSmaller" : toggleHeadingSmaller ,
"toggleHeadingBigger" : toggleHeadingBigger ,
"drawImage" : drawImage ,
"toggleBlockquote" : toggleBlockquote ,
"toggleOrderedList" : toggleOrderedList ,
"toggleUnorderedList" : toggleUnorderedList ,
"toggleCodeBlock" : toggleCodeBlock ,
"togglePreview" : togglePreview ,
2016-01-09 10:13:16 +01:00
"toggleStrikethrough" : toggleStrikethrough ,
"toggleHeading1" : toggleHeading1 ,
"toggleHeading2" : toggleHeading2 ,
"toggleHeading3" : toggleHeading3 ,
"cleanBlock" : cleanBlock ,
"drawTable" : drawTable ,
"drawHorizontalRule" : drawHorizontalRule ,
"undo" : undo ,
"redo" : redo ,
"toggleSideBySide" : toggleSideBySide ,
"toggleFullScreen" : toggleFullScreen
2016-01-07 10:38:19 +01:00
} ;
2015-06-19 22:37:06 +02:00
var shortcuts = {
2016-01-07 10:38:19 +01:00
"toggleBold" : "Cmd-B" ,
"toggleItalic" : "Cmd-I" ,
"drawLink" : "Cmd-K" ,
"toggleHeadingSmaller" : "Cmd-H" ,
"toggleHeadingBigger" : "Shift-Cmd-H" ,
2016-01-09 10:13:16 +01:00
"cleanBlock" : "Cmd-E" ,
2016-01-07 10:38:19 +01:00
"drawImage" : "Cmd-Alt-I" ,
"toggleBlockquote" : "Cmd-'" ,
"toggleOrderedList" : "Cmd-Alt-L" ,
"toggleUnorderedList" : "Cmd-L" ,
"toggleCodeBlock" : "Cmd-Alt-C" ,
"togglePreview" : "Cmd-P" ,
"toggleSideBySide" : "F9" ,
"toggleFullScreen" : "F11"
2015-06-19 22:37:06 +02:00
} ;
2016-01-09 10:13:16 +01:00
var getBindingName = function ( f ) {
for ( var key in bindings ) {
if ( bindings [ key ] === f ) {
return key ;
}
}
return null ;
} ;
2015-10-19 19:53:40 +02:00
var isMobile = function ( ) {
var check = false ;
2015-11-03 17:16:08 +01:00
( function ( a ) {
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 ) || / 1 2 0 7 | 6 3 1 0 | 6 5 9 0 | 3 g s o | 4 t h p | 5 0 [ 1 - 6 ] i | 7 7 0 s | 8 0 2 s | a w a | a b a c | a c ( e r | o o | s \ - ) | a i ( k o | r n ) | a l ( a v | c a | c o ) | a m o i | a n ( e x | n y | y w ) | a p t u | a r ( c h | g o ) | a s ( t e | u s ) | a t t w | a u ( d i | \ - m | r | s ) | a v a n | b e ( c k | l l | n q ) | b i ( l b | r d ) | b l ( a c | a z ) | b r ( e | v ) w | b u m b | b w \ - ( n | u ) | c 5 5 \ / | c a p i | c c w a | c d m \ - | c e l l | c h t m | c l d c | c m d \ - | c o ( m p | n d ) | c r a w | d a ( i t | l l | n g ) | d b t e | d c \ - s | d e v i | d i c a | d m o b | d o ( c | p ) o | d s ( 1 2 | \ - d ) | e l ( 4 9 | a i ) | e m ( l 2 | u l ) | e r ( i c | k 0 ) | e s l 8 | e z ( [ 4 - 7 ] 0 | o s | w a | z e ) | f e t c | f l y ( \ - | _ ) | g 1 u | g 5 6 0 | g e n e | g f \ - 5 | g \ - m o | g o ( \ . w | o d ) | g r ( a d | u n ) | h a i e | h c i t | h d \ - ( m | p | t ) | h e i \ - | h i ( p t | t a ) | h p ( i | i p ) | h s \ - c | h t ( c ( \ - | | _ | a | g | p | s | t ) | t p ) | h u ( a w | t c ) | i \ - ( 2 0 | g o | m a ) | i 2 3 0 | i a c ( | \ - | \ / ) | i b r o | i d e a | i g 0 1 | i k o m | i m 1 k | i n n o | i p a q | i r i s | j a ( t | v ) a | j b r o | j e m u | j i g s | k d d i | k e j i | k g t ( | \ / ) | k l o n | k p t | k w c \ - | k y o ( c | k ) | l e ( n o | x i ) | l g ( g | \ / ( k | l | u ) | 5 0 | 5 4 | \ - [ a - w ] ) | l i b w | l y n x | m 1 \ - w | m 3 g a | m 5 0 \ / | m a ( t e | u i | x o ) | m c ( 0 1 | 2 1 | c a ) | m \ - c r | m e ( r c | r i ) | m i ( o 8 | o a | t s ) | m m e f | m o ( 0 1 | 0 2 | b i | d e | d o | t ( \ - | | o | v ) | z z ) | m t ( 5 0 | p 1 | v ) | m w b p | m y w a | n 1 0 [ 0 - 2 ] | n 2 0 [ 2 - 3 ] | n 3 0 ( 0 | 2 ) | n 5 0 ( 0 | 2 | 5 ) | n 7 ( 0 ( 0 | 1 ) | 1 0 ) | n e ( ( c | m ) \ - | o n | t f | w f | w g | w t ) | n o k ( 6 | i ) | n z p h | o 2 i m | o p ( t i | w v ) | o r a n | o w g 1 | p 8 0 0 | p a n ( a | d | t ) | p d x g | p g ( 1 3 | \ - ( [ 1 - 8 ] | c ) ) | p h i l | p i r e | p l ( a y | u c ) | p n \ - 2 | p o ( c k | r t | s e ) | p r o x | p s i o | p t \ - g | q a \ - a | q c ( 0 7 | 1 2 | 2 1 | 3 2 | 6 0 | \ - [ 2 - 7 ] | i \ - ) | q t e k | r 3 8 0 | r 6 0 0 | r a k s | r i m 9 | r o ( v e | z o ) | s 5 5 \ / | s a ( g e | m a | m m | m s | n y | v a ) | s c ( 0 1 | h \ - | o o | p \ - ) | s d k \ / | s e ( c ( \ - | 0 | 1 ) | 4 7 | m c | n d | r i ) | s g h \ - | s h a r | s i e ( \ - | m ) | s k \ - 0 | s l ( 4 5 | i d ) | s m ( a l | a r | b 3 | i t | t 5 ) | s o ( f t | n y ) | s p ( 0 1 | h \ - | v \ - | v ) | s y ( 0 1 | m b ) | t 2 ( 1 8 | 5 0 ) | t 6 ( 0 0 | 1 0 | 1 8 ) | t a ( g t | l k ) | t c l \ - | t d g \ - | t e l ( i | m ) | t i m \ - | t \ - m o | t o ( p l | s h ) | t s ( 7 0 | m \ - | m 3 | m 5 ) | t x \ - 9 | u p ( \ . b | g 1 | s i ) | u t s t | v 4 0 0 | v 7 5 0 | v e r i | v i ( r g | t e ) | v k ( 4 0 | 5 [ 0 - 3 ] | \ - v ) | v m 4 0 | v o d a | v u l c | v x ( 5 2 | 5 3 | 6 0 | 6 1 | 7 0 | 8 0 | 8 1 | 8 3 | 8 5 | 9 8 ) | w 3 c ( \ - | ) | w e b c | w h i t | w i ( g | n c | n w ) | w m l b | w o n u | x 7 0 0 | y a s \ - | y o u r | z e t o | z t e \ - / i . t e s t ( a . s u b s t r ( 0 , 4 ) ) ) c h e c k = t r u e ;
} ) ( navigator . userAgent || navigator . vendor || window . opera ) ;
2015-10-19 19:53:40 +02:00
return check ;
} ;
2015-10-08 04:13:38 +02:00
2015-06-19 22:37:06 +02:00
/ * *
* Fix shortcut . Mac use Command , others use Ctrl .
* /
function fixShortcut ( name ) {
2015-08-11 19:04:59 +02:00
if ( isMac ) {
2015-10-07 22:52:14 +02:00
name = name . replace ( "Ctrl" , "Cmd" ) ;
2015-06-19 22:43:21 +02:00
} else {
2015-10-07 22:52:14 +02:00
name = name . replace ( "Cmd" , "Ctrl" ) ;
2015-06-19 22:43:21 +02:00
}
return name ;
2015-06-19 22:37:06 +02:00
}
/ * *
* Create icon element for toolbar .
* /
2016-01-07 10:38:19 +01:00
function createIcon ( options , enableTooltips , shortcuts ) {
2015-06-19 22:43:21 +02:00
options = options || { } ;
2015-10-07 22:52:14 +02:00
var el = document . createElement ( "a" ) ;
2015-07-14 07:47:34 +02:00
enableTooltips = ( enableTooltips == undefined ) ? true : enableTooltips ;
2015-07-21 15:28:36 +02:00
2015-08-11 19:04:59 +02:00
if ( options . title && enableTooltips ) {
2016-01-09 10:13:16 +01:00
el . title = createTootlip ( options . title , options . action , shortcuts ) ;
2015-07-21 15:28:36 +02:00
2015-08-11 19:04:59 +02:00
if ( isMac ) {
2015-10-07 22:52:14 +02:00
el . title = el . title . replace ( "Ctrl" , "⌘" ) ;
el . title = el . title . replace ( "Alt" , "⌥" ) ;
2015-06-19 22:43:21 +02:00
}
2015-06-19 22:37:06 +02:00
}
2015-12-05 06:41:24 +01:00
el . tabIndex = - 1 ;
2015-07-14 18:52:28 +02:00
el . className = options . className ;
2015-06-19 22:43:21 +02:00
return el ;
2015-06-19 22:37:06 +02:00
}
function createSep ( ) {
2015-10-07 22:52:14 +02:00
var el = document . createElement ( "i" ) ;
el . className = "separator" ;
el . innerHTML = "|" ;
2015-06-19 22:43:21 +02:00
return el ;
2015-06-19 22:37:06 +02:00
}
2016-01-09 10:13:16 +01:00
function createTootlip ( title , action , shortcuts ) {
var actionName ;
var tooltip = title ;
if ( action ) {
actionName = getBindingName ( action ) ;
if ( shortcuts [ actionName ] ) {
tooltip += " (" + fixShortcut ( shortcuts [ actionName ] ) + ")" ;
}
}
return tooltip ;
}
2015-06-19 22:37:06 +02:00
/ * *
* The state of CodeMirror at the given position .
* /
function getState ( cm , pos ) {
2015-10-07 22:52:14 +02:00
pos = pos || cm . getCursor ( "start" ) ;
2015-06-19 22:43:21 +02:00
var stat = cm . getTokenAt ( pos ) ;
2015-08-11 19:04:59 +02:00
if ( ! stat . type ) return { } ;
2015-06-19 22:43:21 +02:00
2015-10-07 22:52:14 +02:00
var types = stat . type . split ( " " ) ;
2015-06-19 22:43:21 +02:00
var ret = { } ,
data , text ;
2015-08-11 19:04:59 +02:00
for ( var i = 0 ; i < types . length ; i ++ ) {
2015-06-19 22:43:21 +02:00
data = types [ i ] ;
2015-10-07 22:52:14 +02:00
if ( data === "strong" ) {
2015-06-19 22:43:21 +02:00
ret . bold = true ;
2015-10-07 22:52:14 +02:00
} else if ( data === "variable-2" ) {
2015-06-19 22:43:21 +02:00
text = cm . getLine ( pos . line ) ;
2015-08-11 19:04:59 +02:00
if ( /^\s*\d+\.\s/ . test ( text ) ) {
2015-10-07 22:52:14 +02:00
ret [ "ordered-list" ] = true ;
2015-06-19 22:43:21 +02:00
} else {
2015-10-07 22:52:14 +02:00
ret [ "unordered-list" ] = true ;
2015-06-19 22:43:21 +02:00
}
2015-10-07 22:52:14 +02:00
} else if ( data === "atom" ) {
2015-06-19 22:43:21 +02:00
ret . quote = true ;
2015-10-07 22:52:14 +02:00
} else if ( data === "em" ) {
2015-06-19 22:43:21 +02:00
ret . italic = true ;
2015-10-07 22:52:14 +02:00
} else if ( data === "quote" ) {
2015-06-19 22:43:21 +02:00
ret . quote = true ;
2015-10-07 22:52:14 +02:00
} else if ( data === "strikethrough" ) {
2015-09-01 07:51:40 +02:00
ret . strikethrough = true ;
2015-10-07 22:52:14 +02:00
} else if ( data === "comment" ) {
2015-09-14 20:16:58 +02:00
ret . code = true ;
2016-01-20 21:50:59 +01:00
} else if ( data === "link" ) {
ret . link = true ;
} else if ( data === "tag" ) {
ret . image = true ;
} else if ( data . match ( /^header(\-[1-6])?$/ ) ) {
ret [ data . replace ( "header" , "heading" ) ] = true ;
2015-06-19 22:43:21 +02:00
}
2015-06-19 22:37:06 +02:00
}
2015-06-19 22:43:21 +02:00
return ret ;
2015-06-19 22:37:06 +02:00
}
2015-09-02 08:21:48 +02:00
// Saved overflow setting
var saved _overflow = "" ;
2015-06-19 22:37:06 +02:00
/ * *
* Toggle full screen of the editor .
* /
function toggleFullScreen ( editor ) {
2015-08-17 23:06:04 +02:00
// Set fullscreen
2015-08-08 20:14:04 +02:00
var cm = editor . codemirror ;
cm . setOption ( "fullScreen" , ! cm . getOption ( "fullScreen" ) ) ;
2015-09-02 17:23:15 +02:00
2015-09-02 08:21:48 +02:00
// Prevent scrolling on body during fullscreen active
2015-09-02 17:23:15 +02:00
if ( cm . getOption ( "fullScreen" ) ) {
2015-09-02 08:21:48 +02:00
saved _overflow = document . body . style . overflow ;
document . body . style . overflow = "hidden" ;
} else {
document . body . style . overflow = saved _overflow ;
}
2015-09-02 03:26:52 +02:00
2015-08-17 23:06:04 +02:00
// Update toolbar class
var wrap = cm . getWrapperElement ( ) ;
2015-09-02 03:26:52 +02:00
2015-08-17 23:06:04 +02:00
if ( ! /fullscreen/ . test ( wrap . previousSibling . className ) ) {
wrap . previousSibling . className += " fullscreen" ;
} else {
wrap . previousSibling . className = wrap . previousSibling . className . replace ( /\s*fullscreen\b/ , "" ) ;
}
2015-07-21 15:28:36 +02:00
2015-09-02 03:26:52 +02:00
2015-08-17 23:06:04 +02:00
// Update toolbar button
2015-08-08 20:14:04 +02:00
var toolbarButton = editor . toolbarElements . fullscreen ;
2015-07-21 15:28:36 +02:00
2015-08-11 19:04:59 +02:00
if ( ! /active/ . test ( toolbarButton . className ) ) {
2015-08-08 20:14:04 +02:00
toolbarButton . className += " active" ;
2015-08-11 19:04:59 +02:00
} else {
2015-10-07 22:52:14 +02:00
toolbarButton . className = toolbarButton . className . replace ( /\s*active\s*/g , "" ) ;
2015-06-19 22:37:06 +02:00
}
2015-09-02 03:26:52 +02:00
2015-09-01 08:40:33 +02:00
// Hide side by side if needed
var sidebyside = cm . getWrapperElement ( ) . nextSibling ;
2015-09-02 03:26:52 +02:00
if ( /editor-preview-active-side/ . test ( sidebyside . className ) )
2015-09-01 08:40:33 +02:00
toggleSideBySide ( editor ) ;
2015-06-19 22:37:06 +02:00
}
/ * *
* Action for toggling bold .
* /
function toggleBold ( editor ) {
2015-11-29 21:11:54 +01:00
_toggleBlock ( editor , "bold" , editor . options . blockStyles . bold ) ;
2015-06-19 22:37:06 +02:00
}
/ * *
* Action for toggling italic .
* /
function toggleItalic ( editor ) {
2015-11-29 21:11:54 +01:00
_toggleBlock ( editor , "italic" , editor . options . blockStyles . italic ) ;
2015-06-19 22:37:06 +02:00
}
2015-09-01 07:51:40 +02:00
/ * *
* Action for toggling strikethrough .
* /
function toggleStrikethrough ( editor ) {
2015-10-07 22:52:14 +02:00
_toggleBlock ( editor , "strikethrough" , "~~" ) ;
2015-09-01 07:51:40 +02:00
}
2015-06-19 22:37:06 +02:00
/ * *
* Action for toggling code block .
* /
function toggleCodeBlock ( editor ) {
2016-01-20 00:09:19 +01:00
var fenceCharsToInsert = editor . options . blockStyles . code ;
function fencing _line ( line ) {
/* return true, if this is a ``` or ~~~ line */
if ( typeof line !== "object" ) {
throw "fencing_line() takes a 'line' object (not a line number, or line text). Got: " + typeof line + ": " + line ;
}
return line . styles && line . styles [ 2 ] && line . styles [ 2 ] . indexOf ( "formatting-code-block" ) !== - 1 ;
}
2016-01-20 23:02:04 +01:00
function token _state ( token ) {
// base goes an extra level deep when mode backdrops are used, e.g. spellchecker on
return token . state . base . base || token . state . base ;
}
2016-01-20 00:09:19 +01:00
function code _type ( cm , line _num , line , firstTok , lastTok ) {
/ *
* Return "single" , "indented" , "fenced" or false
*
* cm and line _num are required . Others are optional for efficiency
* To check in the middle of a line , pass in firstTok yourself .
* /
line = line || cm . getLineHandle ( line _num ) ;
firstTok = firstTok || cm . getTokenAt ( {
line : line _num ,
ch : 1
} ) ;
lastTok = lastTok || ( ! ! line . text && cm . getTokenAt ( {
line : line _num ,
ch : line . text . length - 1
} ) ) ;
var types = firstTok . type ? firstTok . type . split ( " " ) : [ ] ;
2016-01-20 23:02:04 +01:00
if ( lastTok && token _state ( lastTok ) . indentedCode ) {
2016-01-20 00:09:19 +01:00
// have to check last char, since first chars of first line aren"t marked as indented
return "indented" ;
} else if ( types . indexOf ( "comment" ) === - 1 ) {
// has to be after "indented" check, since first chars of first indented line aren"t marked as such
return false ;
2016-01-20 23:02:04 +01:00
} else if ( token _state ( firstTok ) . fencedChars || token _state ( lastTok ) . fencedChars || fencing _line ( line ) ) {
2016-01-20 00:09:19 +01:00
return "fenced" ;
} else {
return "single" ;
}
}
function insertFencingAtSelection ( cm , cur _start , cur _end , fenceCharsToInsert ) {
var start _line _sel = cur _start . line + 1 ,
end _line _sel = cur _end . line + 1 ,
sel _multi = cur _start . line !== cur _end . line ,
repl _start = fenceCharsToInsert + "\n" ,
repl _end = "\n" + fenceCharsToInsert ;
if ( sel _multi ) {
end _line _sel ++ ;
}
// handle last char including \n or not
if ( sel _multi && cur _end . ch === 0 ) {
repl _end = fenceCharsToInsert + "\n" ;
end _line _sel -- ;
}
_replaceSelection ( cm , false , [ repl _start , repl _end ] ) ;
cm . setSelection ( {
line : start _line _sel ,
ch : 0
} , {
line : end _line _sel ,
ch : 0
} ) ;
}
var cm = editor . codemirror ,
cur _start = cm . getCursor ( "start" ) ,
cur _end = cm . getCursor ( "end" ) ,
tok = cm . getTokenAt ( {
line : cur _start . line ,
ch : cur _start . ch || 1
} ) , // avoid ch 0 which is a cursor pos but not token
line = cm . getLineHandle ( cur _start . line ) ,
is _code = code _type ( cm , cur _start . line , line , tok ) ;
var block _start , block _end , lineCount ;
if ( is _code === "single" ) {
// similar to some SimpleMDE _toggleBlock logic
var start = line . text . slice ( 0 , cur _start . ch ) . replace ( "`" , "" ) ,
end = line . text . slice ( cur _start . ch ) . replace ( "`" , "" ) ;
cm . replaceRange ( start + end , {
line : cur _start . line ,
ch : 0
} , {
line : cur _start . line ,
ch : 99999999999999
} ) ;
cur _start . ch -- ;
if ( cur _start !== cur _end ) {
cur _end . ch -- ;
}
cm . setSelection ( cur _start , cur _end ) ;
cm . focus ( ) ;
} else if ( is _code === "fenced" ) {
if ( cur _start . line !== cur _end . line || cur _start . ch !== cur _end . ch ) {
// use selection
2016-01-25 23:36:16 +01:00
// find the fenced line so we know what type it is (tilde, backticks, number of them)
2016-01-20 00:09:19 +01:00
for ( block _start = cur _start . line ; block _start >= 0 ; block _start -- ) {
line = cm . getLineHandle ( block _start ) ;
if ( fencing _line ( line ) ) {
break ;
}
}
var fencedTok = cm . getTokenAt ( {
line : block _start ,
ch : 1
} ) ;
2016-01-25 23:36:16 +01:00
var fence _chars = token _state ( fencedTok ) . fencedChars ;
var start _text , start _line ;
var end _text , end _line ;
// check for selection going up against fenced lines, in which case we don't want to add more fencing
if ( fencing _line ( cm . getLineHandle ( cur _start . line ) ) ) {
start _text = "" ;
start _line = cur _start . line ;
} else if ( fencing _line ( cm . getLineHandle ( cur _start . line - 1 ) ) ) {
start _text = "" ;
start _line = cur _start . line - 1 ;
} else {
start _text = fence _chars + "\n" ;
start _line = cur _start . line ;
}
if ( fencing _line ( cm . getLineHandle ( cur _end . line ) ) ) {
end _text = "" ;
end _line = cur _end . line ;
if ( cur _end . ch === 0 ) {
end _line += 1 ;
}
} else if ( cur _end . ch !== 0 && fencing _line ( cm . getLineHandle ( cur _end . line + 1 ) ) ) {
end _text = "" ;
end _line = cur _end . line + 1 ;
} else {
end _text = fence _chars + "\n" ;
end _line = cur _end . line + 1 ;
}
if ( cur _end . ch === 0 ) {
// full last line selected, putting cursor at beginning of next
end _line -= 1 ;
}
cm . operation ( function ( ) {
// end line first, so that line numbers don't change
cm . replaceRange ( end _text , {
line : end _line ,
ch : 0
} , {
line : end _line + ( end _text ? 0 : 1 ) ,
ch : 0
} ) ;
cm . replaceRange ( start _text , {
line : start _line ,
ch : 0
} , {
line : start _line + ( start _text ? 0 : 1 ) ,
ch : 0
} ) ;
} ) ;
cm . setSelection ( {
line : start _line + ( start _text ? 1 : 0 ) ,
ch : 0
} , {
line : end _line + ( start _text ? 1 : - 1 ) ,
ch : 0
} ) ;
cm . focus ( ) ;
2016-01-20 00:09:19 +01:00
} else {
// no selection, search for ends of this fenced block
var search _from = cur _start . line ;
if ( fencing _line ( cm . getLineHandle ( cur _start . line ) ) ) { // gets a little tricky if cursor is right on a fenced line
if ( code _type ( cm , cur _start . line + 1 ) === "fenced" ) {
block _start = cur _start . line ;
search _from = cur _start . line + 1 ; // for searching for "end"
} else {
block _end = cur _start . line ;
search _from = cur _start . line - 1 ; // for searching for "start"
}
}
if ( block _start === undefined ) {
for ( block _start = search _from ; block _start >= 0 ; block _start -- ) {
line = cm . getLineHandle ( block _start ) ;
if ( fencing _line ( line ) ) {
break ;
}
}
}
if ( block _end === undefined ) {
lineCount = cm . lineCount ( ) ;
for ( block _end = search _from ; block _end < lineCount ; block _end ++ ) {
line = cm . getLineHandle ( block _end ) ;
if ( fencing _line ( line ) ) {
break ;
}
}
}
cm . operation ( function ( ) {
cm . replaceRange ( "" , {
line : block _start ,
ch : 0
} , {
line : block _start + 1 ,
ch : 0
} ) ;
cm . replaceRange ( "" , {
line : block _end - 1 ,
ch : 0
} , {
line : block _end ,
ch : 0
} ) ;
} ) ;
cm . focus ( ) ;
}
} else if ( is _code === "indented" ) {
if ( cur _start . line !== cur _end . line || cur _start . ch !== cur _end . ch ) {
// use selection
block _start = cur _start . line ;
block _end = cur _end . line ;
if ( cur _end . ch === 0 ) {
block _end -- ;
}
} else {
// no selection, search for ends of this indented block
for ( block _start = cur _start . line ; block _start >= 0 ; block _start -- ) {
line = cm . getLineHandle ( block _start ) ;
if ( line . text . match ( /^\s*$/ ) ) {
// empty or all whitespace - keep going
continue ;
} else {
if ( code _type ( cm , block _start , line ) !== "indented" ) {
block _start += 1 ;
break ;
}
}
}
lineCount = cm . lineCount ( ) ;
for ( block _end = cur _start . line ; block _end < lineCount ; block _end ++ ) {
line = cm . getLineHandle ( block _end ) ;
if ( line . text . match ( /^\s*$/ ) ) {
// empty or all whitespace - keep going
continue ;
} else {
if ( code _type ( cm , block _end , line ) !== "indented" ) {
block _end -= 1 ;
break ;
}
}
}
}
// if we are going to un-indent based on a selected set of lines, and the next line is indented too, we need to
// insert a blank line so that the next line(s) continue to be indented code
var next _line = cm . getLineHandle ( block _end + 1 ) ,
next _line _last _tok = next _line && cm . getTokenAt ( {
line : block _end + 1 ,
ch : next _line . text . length - 1
} ) ,
2016-01-20 23:02:04 +01:00
next _line _indented = next _line _last _tok && token _state ( next _line _last _tok ) . indentedCode ;
2016-01-20 00:09:19 +01:00
if ( next _line _indented ) {
cm . replaceRange ( "\n" , {
line : block _end + 1 ,
ch : 0
} ) ;
}
for ( var i = block _start ; i <= block _end ; i ++ ) {
cm . indentLine ( i , "subtract" ) ; // TODO: this doesn't get tracked in the history, so can't be undone :(
}
cm . focus ( ) ;
} else {
// insert code formatting
var no _sel _and _starting _of _line = ( cur _start . line === cur _end . line && cur _start . ch === cur _end . ch && cur _start . ch === 0 ) ;
var sel _multi = cur _start . line !== cur _end . line ;
if ( no _sel _and _starting _of _line || sel _multi ) {
insertFencingAtSelection ( cm , cur _start , cur _end , fenceCharsToInsert ) ;
} else {
_replaceSelection ( cm , false , [ "`" , "`" ] ) ;
}
}
2015-06-19 22:37:06 +02:00
}
/ * *
* Action for toggling blockquote .
* /
function toggleBlockquote ( editor ) {
2015-06-19 22:43:21 +02:00
var cm = editor . codemirror ;
2015-10-07 22:52:14 +02:00
_toggleLine ( cm , "quote" ) ;
2015-06-19 22:37:06 +02:00
}
2015-08-12 18:23:09 +02:00
/ * *
* Action for toggling heading size : normal - > h1 - > h2 - > h3 - > h4 - > h5 - > h6 - > normal
* /
function toggleHeadingSmaller ( editor ) {
var cm = editor . codemirror ;
2015-10-07 22:52:14 +02:00
_toggleHeading ( cm , "smaller" ) ;
2015-08-12 18:23:09 +02:00
}
/ * *
* Action for toggling heading size : normal - > h6 - > h5 - > h4 - > h3 - > h2 - > h1 - > normal
* /
function toggleHeadingBigger ( editor ) {
var cm = editor . codemirror ;
2015-10-07 22:52:14 +02:00
_toggleHeading ( cm , "bigger" ) ;
2015-08-12 18:23:09 +02:00
}
2015-06-19 22:37:06 +02:00
2015-09-01 07:40:11 +02:00
/ * *
* Action for toggling heading size 1
* /
function toggleHeading1 ( editor ) {
var cm = editor . codemirror ;
_toggleHeading ( cm , undefined , 1 ) ;
}
/ * *
* Action for toggling heading size 2
* /
function toggleHeading2 ( editor ) {
var cm = editor . codemirror ;
_toggleHeading ( cm , undefined , 2 ) ;
}
/ * *
* Action for toggling heading size 3
* /
function toggleHeading3 ( editor ) {
var cm = editor . codemirror ;
_toggleHeading ( cm , undefined , 3 ) ;
}
2015-06-19 22:37:06 +02:00
/ * *
* Action for toggling ul .
* /
2015-07-14 18:52:28 +02:00
function toggleUnorderedList ( editor ) {
2015-06-19 22:43:21 +02:00
var cm = editor . codemirror ;
2015-10-07 22:52:14 +02:00
_toggleLine ( cm , "unordered-list" ) ;
2015-06-19 22:37:06 +02:00
}
/ * *
* Action for toggling ol .
* /
function toggleOrderedList ( editor ) {
2015-06-19 22:43:21 +02:00
var cm = editor . codemirror ;
2015-10-07 22:52:14 +02:00
_toggleLine ( cm , "ordered-list" ) ;
2015-06-19 22:37:06 +02:00
}
2016-01-08 14:44:43 +01:00
/ * *
* Action for clean block ( remove headline , list , blockquote code , markers )
* /
function cleanBlock ( editor ) {
var cm = editor . codemirror ;
_cleanBlock ( cm ) ;
}
2015-06-19 22:37:06 +02:00
/ * *
* Action for drawing a link .
* /
function drawLink ( editor ) {
2015-06-19 22:43:21 +02:00
var cm = editor . codemirror ;
var stat = getState ( cm ) ;
2015-11-03 11:36:24 +01:00
var options = editor . options ;
2016-01-25 14:14:46 +01:00
var url = "http://" ;
if ( options . promptURLs ) {
2016-01-26 10:39:27 +01:00
url = prompt ( options . promptTexts . link ) ;
if ( ! url ) {
return false ;
}
2016-01-25 14:14:46 +01:00
}
_replaceSelection ( cm , stat . link , options . insertTexts . link , url ) ;
2015-06-19 22:37:06 +02:00
}
/ * *
* Action for drawing an img .
* /
function drawImage ( editor ) {
2015-06-19 22:43:21 +02:00
var cm = editor . codemirror ;
var stat = getState ( cm ) ;
2015-11-03 11:36:24 +01:00
var options = editor . options ;
2016-01-25 14:14:46 +01:00
var url = "http://" ;
if ( options . promptURLs ) {
2016-01-26 10:39:27 +01:00
url = prompt ( options . promptTexts . image ) ;
if ( ! url ) {
return false ;
}
2016-01-25 14:14:46 +01:00
}
_replaceSelection ( cm , stat . image , options . insertTexts . image , url ) ;
2015-06-19 22:37:06 +02:00
}
2015-11-24 18:54:41 +01:00
/ * *
* Action for drawing a table .
* /
function drawTable ( editor ) {
var cm = editor . codemirror ;
var stat = getState ( cm ) ;
var options = editor . options ;
_replaceSelection ( cm , stat . table , options . insertTexts . table ) ;
}
2015-07-14 19:34:22 +02:00
/ * *
* Action for drawing a horizontal rule .
* /
function drawHorizontalRule ( editor ) {
var cm = editor . codemirror ;
var stat = getState ( cm ) ;
2015-11-03 11:36:24 +01:00
var options = editor . options ;
2015-11-03 18:31:22 +01:00
_replaceSelection ( cm , stat . image , options . insertTexts . horizontalRule ) ;
2015-07-14 19:34:22 +02:00
}
2015-06-19 22:37:06 +02:00
/ * *
* Undo action .
* /
function undo ( editor ) {
2015-06-19 22:43:21 +02:00
var cm = editor . codemirror ;
cm . undo ( ) ;
cm . focus ( ) ;
2015-06-19 22:37:06 +02:00
}
/ * *
* Redo action .
* /
function redo ( editor ) {
2015-06-19 22:43:21 +02:00
var cm = editor . codemirror ;
cm . redo ( ) ;
cm . focus ( ) ;
2015-06-19 22:37:06 +02:00
}
2015-09-01 08:40:33 +02:00
/ * *
* Toggle side by side preview
* /
function toggleSideBySide ( editor ) {
var cm = editor . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
var preview = wrapper . nextSibling ;
var toolbarButton = editor . toolbarElements [ "side-by-side" ] ;
2015-12-18 23:25:47 +01:00
var useSideBySideListener = false ;
2015-09-02 03:26:52 +02:00
if ( /editor-preview-active-side/ . test ( preview . className ) ) {
2015-09-01 08:40:33 +02:00
preview . className = preview . className . replace (
2015-10-07 22:52:14 +02:00
/\s*editor-preview-active-side\s*/g , ""
2015-09-01 08:40:33 +02:00
) ;
2015-10-07 22:52:14 +02:00
toolbarButton . className = toolbarButton . className . replace ( /\s*active\s*/g , "" ) ;
wrapper . className = wrapper . className . replace ( /\s*CodeMirror-sided\s*/g , " " ) ;
2015-09-01 08:40:33 +02:00
} else {
2015-10-19 19:53:40 +02:00
// When the preview button is clicked for the first time,
// give some time for the transition from editor.css to fire and the view to slide from right to left,
// instead of just appearing.
2015-09-01 08:40:33 +02:00
setTimeout ( function ( ) {
2015-09-25 22:49:54 +02:00
if ( ! cm . getOption ( "fullScreen" ) )
toggleFullScreen ( editor ) ;
2015-10-07 22:52:14 +02:00
preview . className += " editor-preview-active-side" ;
2015-09-01 08:40:33 +02:00
} , 1 ) ;
2015-10-07 22:52:14 +02:00
toolbarButton . className += " active" ;
wrapper . className += " CodeMirror-sided" ;
2015-12-18 23:25:47 +01:00
useSideBySideListener = true ;
2015-09-01 08:40:33 +02:00
}
2015-09-02 03:26:52 +02:00
2015-09-01 08:40:33 +02:00
// Hide normal preview if active
var previewNormal = wrapper . lastChild ;
if ( /editor-preview-active/ . test ( previewNormal . className ) ) {
previewNormal . className = previewNormal . className . replace (
2015-10-07 22:52:14 +02:00
/\s*editor-preview-active\s*/g , ""
2015-09-01 08:40:33 +02:00
) ;
var toolbar = editor . toolbarElements . preview ;
var toolbar _div = wrapper . previousSibling ;
2015-10-07 22:52:14 +02:00
toolbar . className = toolbar . className . replace ( /\s*active\s*/g , "" ) ;
toolbar _div . className = toolbar _div . className . replace ( /\s*disabled-for-preview*/g , "" ) ;
2015-09-01 08:40:33 +02:00
}
2015-12-18 23:25:47 +01:00
var sideBySideRenderingFunction = function ( ) {
2015-09-05 21:28:50 +02:00
preview . innerHTML = editor . options . previewRender ( editor . value ( ) , preview ) ;
2015-12-18 09:32:50 +01:00
} ;
2015-09-01 08:40:33 +02:00
2015-12-18 23:25:47 +01:00
if ( ! cm . sideBySideRenderingFunction ) {
cm . sideBySideRenderingFunction = sideBySideRenderingFunction ;
2015-12-18 09:32:50 +01:00
}
2016-01-03 09:14:18 +01:00
2015-12-18 23:33:04 +01:00
if ( useSideBySideListener ) {
2015-09-05 21:28:50 +02:00
preview . innerHTML = editor . options . previewRender ( editor . value ( ) , preview ) ;
2015-12-18 23:25:47 +01:00
cm . on ( "update" , cm . sideBySideRenderingFunction ) ;
2015-12-18 09:32:50 +01:00
} else {
2015-12-18 23:25:47 +01:00
cm . off ( "update" , cm . sideBySideRenderingFunction ) ;
2015-12-18 09:32:50 +01:00
}
2015-09-01 08:40:33 +02:00
}
2015-06-19 22:37:06 +02:00
/ * *
* Preview action .
* /
function togglePreview ( editor ) {
2015-06-19 22:43:21 +02:00
var cm = editor . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
2015-08-11 17:00:14 +02:00
var toolbar _div = wrapper . previousSibling ;
2016-01-23 23:40:31 +01:00
var toolbar = editor . options . toolbar ? editor . toolbarElements . preview : false ;
2015-06-19 22:43:21 +02:00
var preview = wrapper . lastChild ;
2015-09-10 08:29:00 +02:00
if ( ! preview || ! /editor-preview/ . test ( preview . className ) ) {
2015-10-07 22:52:14 +02:00
preview = document . createElement ( "div" ) ;
preview . className = "editor-preview" ;
2015-06-19 22:43:21 +02:00
wrapper . appendChild ( preview ) ;
}
2015-08-11 19:04:59 +02:00
if ( /editor-preview-active/ . test ( preview . className ) ) {
2015-06-19 22:43:21 +02:00
preview . className = preview . className . replace (
2015-10-07 22:52:14 +02:00
/\s*editor-preview-active\s*/g , ""
2015-06-19 22:43:21 +02:00
) ;
2016-01-23 23:40:31 +01:00
if ( toolbar ) {
toolbar . className = toolbar . className . replace ( /\s*active\s*/g , "" ) ;
toolbar _div . className = toolbar _div . className . replace ( /\s*disabled-for-preview*/g , "" ) ;
}
2015-06-19 22:43:21 +02:00
} else {
2015-10-19 19:53:40 +02:00
// When the preview button is clicked for the first time,
// give some time for the transition from editor.css to fire and the view to slide from right to left,
// instead of just appearing.
2015-06-19 22:43:21 +02:00
setTimeout ( function ( ) {
2015-10-07 22:52:14 +02:00
preview . className += " editor-preview-active" ;
2015-06-19 22:43:21 +02:00
} , 1 ) ;
2016-01-23 23:40:31 +01:00
if ( toolbar ) {
toolbar . className += " active" ;
toolbar _div . className += " disabled-for-preview" ;
}
2015-06-19 22:43:21 +02:00
}
2015-09-05 21:28:50 +02:00
preview . innerHTML = editor . options . previewRender ( editor . value ( ) , preview ) ;
2015-09-02 03:26:52 +02:00
2015-09-01 08:40:33 +02:00
// Turn off side by side if needed
var sidebyside = cm . getWrapperElement ( ) . nextSibling ;
2015-09-02 03:26:52 +02:00
if ( /editor-preview-active-side/ . test ( sidebyside . className ) )
2015-09-01 08:40:33 +02:00
toggleSideBySide ( editor ) ;
2015-06-19 22:37:06 +02:00
}
2016-01-25 14:14:46 +01:00
function _replaceSelection ( cm , active , startEnd , url ) {
2015-08-11 19:04:59 +02:00
if ( /editor-preview-active/ . test ( cm . getWrapperElement ( ) . lastChild . className ) )
2015-06-23 03:18:07 +02:00
return ;
2015-07-21 15:28:36 +02:00
2015-06-19 22:43:21 +02:00
var text ;
2015-11-03 11:36:24 +01:00
var start = startEnd [ 0 ] ;
var end = startEnd [ 1 ] ;
2015-10-07 22:52:14 +02:00
var startPoint = cm . getCursor ( "start" ) ;
var endPoint = cm . getCursor ( "end" ) ;
2016-01-25 14:14:46 +01:00
if ( url ) {
end = end . replace ( "#url#" , url ) ;
}
2015-08-11 19:04:59 +02:00
if ( active ) {
2015-06-19 22:43:21 +02:00
text = cm . getLine ( startPoint . line ) ;
start = text . slice ( 0 , startPoint . ch ) ;
end = text . slice ( startPoint . ch ) ;
cm . replaceRange ( start + end , {
line : startPoint . line ,
ch : 0
} ) ;
} else {
text = cm . getSelection ( ) ;
cm . replaceSelection ( start + text + end ) ;
startPoint . ch += start . length ;
2015-09-10 23:54:41 +02:00
if ( startPoint !== endPoint ) {
endPoint . ch += start . length ;
}
2015-06-19 22:43:21 +02:00
}
cm . setSelection ( startPoint , endPoint ) ;
cm . focus ( ) ;
2015-06-19 22:37:06 +02:00
}
2015-09-01 07:40:11 +02:00
function _toggleHeading ( cm , direction , size ) {
2015-08-12 18:23:09 +02:00
if ( /editor-preview-active/ . test ( cm . getWrapperElement ( ) . lastChild . className ) )
return ;
2015-10-07 22:52:14 +02:00
var startPoint = cm . getCursor ( "start" ) ;
var endPoint = cm . getCursor ( "end" ) ;
2015-08-12 18:23:09 +02:00
for ( var i = startPoint . line ; i <= endPoint . line ; i ++ ) {
( function ( i ) {
var text = cm . getLine ( i ) ;
var currHeadingLevel = text . search ( /[^#]/ ) ;
2015-09-02 03:26:52 +02:00
if ( direction !== undefined ) {
if ( currHeadingLevel <= 0 ) {
2015-10-07 22:52:14 +02:00
if ( direction == "bigger" ) {
text = "###### " + text ;
2015-09-01 07:40:11 +02:00
} else {
2015-10-07 22:52:14 +02:00
text = "# " + text ;
2015-09-01 07:40:11 +02:00
}
2015-10-07 22:52:14 +02:00
} else if ( currHeadingLevel == 6 && direction == "smaller" ) {
2015-09-01 07:40:11 +02:00
text = text . substr ( 7 ) ;
2015-10-07 22:52:14 +02:00
} else if ( currHeadingLevel == 1 && direction == "bigger" ) {
2015-09-01 07:40:11 +02:00
text = text . substr ( 2 ) ;
2015-08-12 18:23:09 +02:00
} else {
2015-10-07 22:52:14 +02:00
if ( direction == "bigger" ) {
2015-09-01 07:40:11 +02:00
text = text . substr ( 1 ) ;
} else {
2015-10-07 22:52:14 +02:00
text = "#" + text ;
2015-09-01 07:40:11 +02:00
}
2015-08-12 18:23:09 +02:00
}
2015-09-02 03:26:52 +02:00
} else {
if ( size == 1 ) {
if ( currHeadingLevel <= 0 ) {
2015-10-07 22:52:14 +02:00
text = "# " + text ;
2015-09-02 03:26:52 +02:00
} else if ( currHeadingLevel == size ) {
2015-09-01 07:40:11 +02:00
text = text . substr ( currHeadingLevel + 1 ) ;
2015-09-02 03:26:52 +02:00
} else {
2015-10-07 22:52:14 +02:00
text = "# " + text . substr ( currHeadingLevel + 1 ) ;
2015-09-01 07:40:11 +02:00
}
2015-09-02 03:26:52 +02:00
} else if ( size == 2 ) {
if ( currHeadingLevel <= 0 ) {
2015-10-07 22:52:14 +02:00
text = "## " + text ;
2015-09-02 03:26:52 +02:00
} else if ( currHeadingLevel == size ) {
2015-09-01 07:40:11 +02:00
text = text . substr ( currHeadingLevel + 1 ) ;
2015-09-02 03:26:52 +02:00
} else {
2015-10-07 22:52:14 +02:00
text = "## " + text . substr ( currHeadingLevel + 1 ) ;
2015-09-01 07:40:11 +02:00
}
2015-09-02 03:26:52 +02:00
} else {
if ( currHeadingLevel <= 0 ) {
2015-10-07 22:52:14 +02:00
text = "### " + text ;
2015-09-02 03:26:52 +02:00
} else if ( currHeadingLevel == size ) {
2015-09-01 07:40:11 +02:00
text = text . substr ( currHeadingLevel + 1 ) ;
2015-09-02 03:26:52 +02:00
} else {
2015-10-07 22:52:14 +02:00
text = "### " + text . substr ( currHeadingLevel + 1 ) ;
2015-09-01 07:40:11 +02:00
}
2015-08-12 18:23:09 +02:00
}
}
2015-09-02 03:26:52 +02:00
2015-08-12 18:23:09 +02:00
cm . replaceRange ( text , {
line : i ,
ch : 0
} , {
line : i ,
ch : 99999999999999
} ) ;
} ) ( i ) ;
}
cm . focus ( ) ;
}
2015-06-19 22:37:06 +02:00
function _toggleLine ( cm , name ) {
2015-08-11 19:04:59 +02:00
if ( /editor-preview-active/ . test ( cm . getWrapperElement ( ) . lastChild . className ) )
2015-06-23 03:18:07 +02:00
return ;
2015-07-21 15:28:36 +02:00
2015-06-19 22:43:21 +02:00
var stat = getState ( cm ) ;
2015-10-07 22:52:14 +02:00
var startPoint = cm . getCursor ( "start" ) ;
var endPoint = cm . getCursor ( "end" ) ;
2015-06-19 22:43:21 +02:00
var repl = {
2015-10-07 22:52:14 +02:00
"quote" : /^(\s*)\>\s+/ ,
"unordered-list" : /^(\s*)(\*|\-|\+)\s+/ ,
"ordered-list" : /^(\s*)\d+\.\s+/
2015-06-19 22:43:21 +02:00
} ;
var map = {
2015-10-07 22:52:14 +02:00
"quote" : "> " ,
"unordered-list" : "* " ,
"ordered-list" : "1. "
2015-06-19 22:43:21 +02:00
} ;
2015-08-11 19:04:59 +02:00
for ( var i = startPoint . line ; i <= endPoint . line ; i ++ ) {
2015-06-19 22:43:21 +02:00
( function ( i ) {
var text = cm . getLine ( i ) ;
2015-08-11 19:04:59 +02:00
if ( stat [ name ] ) {
2015-10-07 22:52:14 +02:00
text = text . replace ( repl [ name ] , "$1" ) ;
2015-06-19 22:43:21 +02:00
} else {
text = map [ name ] + text ;
}
cm . replaceRange ( text , {
line : i ,
ch : 0
} , {
line : i ,
ch : 99999999999999
} ) ;
} ) ( i ) ;
}
cm . focus ( ) ;
2015-06-19 22:37:06 +02:00
}
2015-06-19 22:43:21 +02:00
function _toggleBlock ( editor , type , start _chars , end _chars ) {
2015-08-11 19:04:59 +02:00
if ( /editor-preview-active/ . test ( editor . codemirror . getWrapperElement ( ) . lastChild . className ) )
2015-06-23 03:18:07 +02:00
return ;
2015-07-21 15:28:36 +02:00
2015-10-07 22:52:14 +02:00
end _chars = ( typeof end _chars === "undefined" ) ? start _chars : end _chars ;
2015-06-19 22:43:21 +02:00
var cm = editor . codemirror ;
var stat = getState ( cm ) ;
var text ;
var start = start _chars ;
var end = end _chars ;
2015-10-07 22:52:14 +02:00
var startPoint = cm . getCursor ( "start" ) ;
var endPoint = cm . getCursor ( "end" ) ;
2015-06-19 22:43:21 +02:00
2015-08-11 19:04:59 +02:00
if ( stat [ type ] ) {
2015-06-19 22:43:21 +02:00
text = cm . getLine ( startPoint . line ) ;
start = text . slice ( 0 , startPoint . ch ) ;
end = text . slice ( startPoint . ch ) ;
2015-08-11 19:04:59 +02:00
if ( type == "bold" ) {
2015-06-19 22:43:21 +02:00
start = start . replace ( /(\*\*|__)(?![\s\S]*(\*\*|__))/ , "" ) ;
end = end . replace ( /(\*\*|__)/ , "" ) ;
2015-08-11 19:04:59 +02:00
} else if ( type == "italic" ) {
2015-06-19 22:43:21 +02:00
start = start . replace ( /(\*|_)(?![\s\S]*(\*|_))/ , "" ) ;
end = end . replace ( /(\*|_)/ , "" ) ;
2015-09-01 07:51:40 +02:00
} else if ( type == "strikethrough" ) {
start = start . replace ( /(\*\*|~~)(?![\s\S]*(\*\*|~~))/ , "" ) ;
end = end . replace ( /(\*\*|~~)/ , "" ) ;
2015-06-19 22:43:21 +02:00
}
cm . replaceRange ( start + end , {
line : startPoint . line ,
ch : 0
} , {
line : startPoint . line ,
ch : 99999999999999
} ) ;
2015-09-01 07:51:40 +02:00
if ( type == "bold" || type == "strikethrough" ) {
2015-06-22 22:52:28 +02:00
startPoint . ch -= 2 ;
2015-09-10 23:54:41 +02:00
if ( startPoint !== endPoint ) {
endPoint . ch -= 2 ;
}
2015-08-11 19:04:59 +02:00
} else if ( type == "italic" ) {
2015-06-22 22:52:28 +02:00
startPoint . ch -= 1 ;
2015-09-10 23:54:41 +02:00
if ( startPoint !== endPoint ) {
endPoint . ch -= 1 ;
}
2015-06-22 22:52:28 +02:00
}
2015-06-19 22:43:21 +02:00
} else {
text = cm . getSelection ( ) ;
2015-08-11 19:04:59 +02:00
if ( type == "bold" ) {
2015-06-19 22:43:21 +02:00
text = text . split ( "**" ) . join ( "" ) ;
text = text . split ( "__" ) . join ( "" ) ;
2015-08-11 19:04:59 +02:00
} else if ( type == "italic" ) {
2015-06-19 22:43:21 +02:00
text = text . split ( "*" ) . join ( "" ) ;
text = text . split ( "_" ) . join ( "" ) ;
2015-09-01 07:51:40 +02:00
} else if ( type == "strikethrough" ) {
text = text . split ( "~~" ) . join ( "" ) ;
2015-06-19 22:43:21 +02:00
}
cm . replaceSelection ( start + text + end ) ;
startPoint . ch += start _chars . length ;
endPoint . ch = startPoint . ch + text . length ;
2015-06-19 22:37:06 +02:00
}
2015-06-19 22:43:21 +02:00
cm . setSelection ( startPoint , endPoint ) ;
cm . focus ( ) ;
2015-06-19 22:37:06 +02:00
}
2016-01-08 14:44:43 +01:00
function _cleanBlock ( cm ) {
if ( /editor-preview-active/ . test ( cm . getWrapperElement ( ) . lastChild . className ) )
return ;
var startPoint = cm . getCursor ( "start" ) ;
var endPoint = cm . getCursor ( "end" ) ;
var text ;
2016-01-08 17:42:40 +01:00
for ( var line = startPoint . line ; line <= endPoint . line ; line ++ ) {
2016-01-08 14:44:43 +01:00
text = cm . getLine ( line ) ;
2016-01-08 17:42:40 +01:00
text = text . replace ( /^[ ]*([# ]+|\*|\-|[> ]+|[0-9]+(.|\)))[ ]*/ , "" ) ;
2016-01-08 14:44:43 +01:00
cm . replaceRange ( text , {
line : line ,
ch : 0
} , {
line : line ,
ch : 99999999999999
} ) ;
}
}
2015-11-03 17:16:08 +01:00
// Merge the properties of one object into another.
2015-11-03 11:36:24 +01:00
function _mergeProperties ( target , source ) {
2015-11-03 17:16:08 +01:00
for ( var property in source ) {
if ( source . hasOwnProperty ( property ) ) {
if ( source [ property ] instanceof Array ) {
target [ property ] = source [ property ] . concat ( target [ property ] instanceof Array ? target [ property ] : [ ] ) ;
} else if (
source [ property ] !== null &&
typeof source [ property ] === "object" &&
source [ property ] . constructor === Object
) {
target [ property ] = _mergeProperties ( target [ property ] || { } , source [ property ] ) ;
} else {
target [ property ] = source [ property ] ;
}
}
}
return target ;
2015-11-03 11:36:24 +01:00
}
2015-11-03 17:16:08 +01:00
// Merge an arbitrary number of objects into one.
2015-11-03 11:36:24 +01:00
function extend ( target ) {
2015-11-03 17:16:08 +01:00
for ( var i = 1 ; i < arguments . length ; i ++ ) {
target = _mergeProperties ( target , arguments [ i ] ) ;
}
2015-11-03 11:36:24 +01:00
2015-11-03 17:16:08 +01:00
return target ;
2015-11-03 11:36:24 +01:00
}
2015-06-19 22:37:06 +02:00
/* The right word count in respect for CJK. */
function wordCount ( data ) {
2016-06-07 01:39:01 +02:00
var pattern = /[a-zA-Z0-9_\u0392-\u03c9\u0410-\u04F9]]+|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/g ;
2015-06-19 22:43:21 +02:00
var m = data . match ( pattern ) ;
var count = 0 ;
2015-08-11 19:04:59 +02:00
if ( m === null ) return count ;
for ( var i = 0 ; i < m . length ; i ++ ) {
if ( m [ i ] . charCodeAt ( 0 ) >= 0x4E00 ) {
2015-06-19 22:43:21 +02:00
count += m [ i ] . length ;
} else {
count += 1 ;
}
2015-06-19 22:37:06 +02:00
}
2015-06-19 22:43:21 +02:00
return count ;
2015-06-19 22:37:06 +02:00
}
2015-08-18 15:37:42 +02:00
var toolbarBuiltInButtons = {
2015-08-17 23:34:05 +02:00
"bold" : {
2015-07-14 19:24:42 +02:00
name : "bold" ,
2015-06-19 22:43:21 +02:00
action : toggleBold ,
2015-07-14 07:40:36 +02:00
className : "fa fa-bold" ,
2016-01-09 10:13:16 +01:00
title : "Bold" ,
2015-12-05 07:18:40 +01:00
default : true
2015-08-17 23:34:05 +02:00
} ,
"italic" : {
2015-07-14 19:24:42 +02:00
name : "italic" ,
2015-06-19 22:43:21 +02:00
action : toggleItalic ,
2015-07-14 07:40:36 +02:00
className : "fa fa-italic" ,
2016-01-09 10:13:16 +01:00
title : "Italic" ,
2015-12-05 07:18:40 +01:00
default : true
2015-08-17 23:34:05 +02:00
} ,
2015-09-01 07:51:40 +02:00
"strikethrough" : {
name : "strikethrough" ,
action : toggleStrikethrough ,
className : "fa fa-strikethrough" ,
2016-01-09 10:13:16 +01:00
title : "Strikethrough"
2015-09-01 07:51:40 +02:00
} ,
2015-08-17 23:34:05 +02:00
"heading" : {
name : "heading" ,
2015-08-12 18:23:09 +02:00
action : toggleHeadingSmaller ,
2015-09-01 08:40:33 +02:00
className : "fa fa-header" ,
2016-01-09 10:13:16 +01:00
title : "Heading" ,
2015-12-05 07:18:40 +01:00
default : true
2015-06-19 22:43:21 +02:00
} ,
2015-08-18 11:06:00 +02:00
"heading-smaller" : {
2015-08-18 15:37:42 +02:00
name : "heading-smaller" ,
2015-08-18 11:06:00 +02:00
action : toggleHeadingSmaller ,
2015-09-02 03:35:51 +02:00
className : "fa fa-header fa-header-x fa-header-smaller" ,
2016-01-09 10:13:16 +01:00
title : "Smaller Heading"
2015-08-18 11:06:00 +02:00
} ,
"heading-bigger" : {
2015-08-18 15:37:42 +02:00
name : "heading-bigger" ,
2015-08-18 11:06:00 +02:00
action : toggleHeadingBigger ,
2015-09-02 03:35:51 +02:00
className : "fa fa-header fa-header-x fa-header-bigger" ,
2016-01-09 10:13:16 +01:00
title : "Bigger Heading"
2015-08-18 15:37:42 +02:00
} ,
2015-09-01 07:40:11 +02:00
"heading-1" : {
name : "heading-1" ,
action : toggleHeading1 ,
className : "fa fa-header fa-header-x fa-header-1" ,
2016-01-09 10:13:16 +01:00
title : "Big Heading"
2015-09-01 07:40:11 +02:00
} ,
"heading-2" : {
name : "heading-2" ,
action : toggleHeading2 ,
className : "fa fa-header fa-header-x fa-header-2" ,
2016-01-09 10:13:16 +01:00
title : "Medium Heading"
2015-09-01 07:40:11 +02:00
} ,
"heading-3" : {
name : "heading-3" ,
action : toggleHeading3 ,
className : "fa fa-header fa-header-x fa-header-3" ,
2016-01-09 10:13:16 +01:00
title : "Small Heading"
2015-09-01 07:40:11 +02:00
} ,
2015-12-05 07:18:40 +01:00
"separator-1" : {
name : "separator-1"
} ,
2015-08-18 15:37:42 +02:00
"code" : {
name : "code" ,
action : toggleCodeBlock ,
className : "fa fa-code" ,
2016-01-09 10:13:16 +01:00
title : "Code"
2015-08-18 11:06:00 +02:00
} ,
2015-08-17 23:34:05 +02:00
"quote" : {
2015-07-14 19:24:42 +02:00
name : "quote" ,
2015-06-19 22:43:21 +02:00
action : toggleBlockquote ,
2015-07-14 07:40:36 +02:00
className : "fa fa-quote-left" ,
2016-01-09 10:13:16 +01:00
title : "Quote" ,
2015-12-05 07:18:40 +01:00
default : true
2015-08-17 23:34:05 +02:00
} ,
"unordered-list" : {
2015-07-14 19:24:42 +02:00
name : "unordered-list" ,
2015-07-14 18:52:28 +02:00
action : toggleUnorderedList ,
2015-07-14 07:40:36 +02:00
className : "fa fa-list-ul" ,
2016-01-09 10:13:16 +01:00
title : "Generic List" ,
2015-12-05 07:18:40 +01:00
default : true
2015-08-17 23:34:05 +02:00
} ,
"ordered-list" : {
2015-07-14 19:24:42 +02:00
name : "ordered-list" ,
2015-06-19 22:43:21 +02:00
action : toggleOrderedList ,
2015-07-14 07:40:36 +02:00
className : "fa fa-list-ol" ,
2016-01-09 10:13:16 +01:00
title : "Numbered List" ,
2015-12-05 07:18:40 +01:00
default : true
} ,
2016-01-08 14:44:43 +01:00
"clean-block" : {
name : "clean-block" ,
action : cleanBlock ,
className : "fa fa-eraser fa-clean-block" ,
2016-01-09 10:13:16 +01:00
title : "Clean block"
2016-01-08 14:44:43 +01:00
} ,
2015-12-05 07:18:40 +01:00
"separator-2" : {
name : "separator-2"
2015-06-19 22:43:21 +02:00
} ,
2015-08-17 23:34:05 +02:00
"link" : {
2015-07-14 19:24:42 +02:00
name : "link" ,
2015-06-19 22:43:21 +02:00
action : drawLink ,
2015-07-14 07:40:36 +02:00
className : "fa fa-link" ,
2016-01-09 10:13:16 +01:00
title : "Create Link" ,
2015-12-05 07:18:40 +01:00
default : true
2015-08-17 23:34:05 +02:00
} ,
"image" : {
name : "image" ,
2015-06-19 22:43:21 +02:00
action : drawImage ,
2015-07-14 07:40:36 +02:00
className : "fa fa-picture-o" ,
2016-01-09 10:13:16 +01:00
title : "Insert Image" ,
2015-12-05 07:18:40 +01:00
default : true
2015-06-19 22:43:21 +02:00
} ,
2015-11-24 18:54:41 +01:00
"table" : {
name : "table" ,
action : drawTable ,
className : "fa fa-table" ,
2016-01-09 10:13:16 +01:00
title : "Insert Table"
2015-11-24 18:54:41 +01:00
} ,
2015-08-18 11:06:00 +02:00
"horizontal-rule" : {
name : "horizontal-rule" ,
action : drawHorizontalRule ,
className : "fa fa-minus" ,
2016-01-09 10:13:16 +01:00
title : "Insert Horizontal Line"
2015-08-18 11:06:00 +02:00
} ,
2015-12-05 07:18:40 +01:00
"separator-3" : {
name : "separator-3"
} ,
2015-08-17 23:34:05 +02:00
"preview" : {
2015-07-14 19:24:42 +02:00
name : "preview" ,
2015-06-19 22:43:21 +02:00
action : togglePreview ,
2015-09-25 22:56:49 +02:00
className : "fa fa-eye no-disable" ,
2016-01-09 10:13:16 +01:00
title : "Toggle Preview" ,
2015-12-05 07:18:40 +01:00
default : true
2015-08-17 23:34:05 +02:00
} ,
2015-09-01 08:40:33 +02:00
"side-by-side" : {
name : "side-by-side" ,
action : toggleSideBySide ,
2015-09-25 22:56:49 +02:00
className : "fa fa-columns no-disable no-mobile" ,
2016-01-09 10:13:16 +01:00
title : "Toggle Side by Side" ,
2015-12-05 07:18:40 +01:00
default : true
2015-09-01 08:40:33 +02:00
} ,
2015-08-17 23:34:05 +02:00
"fullscreen" : {
2015-08-08 20:14:04 +02:00
name : "fullscreen" ,
action : toggleFullScreen ,
2015-09-25 22:56:49 +02:00
className : "fa fa-arrows-alt no-disable no-mobile" ,
2016-01-09 10:13:16 +01:00
title : "Toggle Fullscreen" ,
2015-12-05 07:18:40 +01:00
default : true
2015-08-17 23:34:05 +02:00
} ,
2016-01-22 20:16:54 +01:00
"separator-4" : {
name : "separator-4"
} ,
2015-08-17 23:34:05 +02:00
"guide" : {
2015-07-14 19:24:42 +02:00
name : "guide" ,
2016-02-25 21:17:41 +01:00
action : "https://simplemde.com/markdown-guide" ,
2015-07-14 18:31:45 +02:00
className : "fa fa-question-circle" ,
2016-01-09 10:13:16 +01:00
title : "Markdown Guide" ,
2015-12-05 07:18:40 +01:00
default : true
2016-01-03 09:14:18 +01:00
} ,
2016-01-22 20:16:54 +01:00
"separator-5" : {
name : "separator-5"
2016-01-03 09:14:18 +01:00
} ,
"undo" : {
name : "undo" ,
action : undo ,
className : "fa fa-undo no-disable" ,
2016-01-09 10:13:16 +01:00
title : "Undo"
2016-01-03 09:14:18 +01:00
} ,
"redo" : {
name : "redo" ,
action : redo ,
className : "fa fa-repeat no-disable" ,
2016-01-09 10:13:16 +01:00
title : "Redo"
2015-07-14 18:52:28 +02:00
}
2015-08-17 23:34:05 +02:00
} ;
2015-11-03 18:31:22 +01:00
var insertTexts = {
2016-01-25 14:14:46 +01:00
link : [ "[" , "](#url#)" ] ,
image : [ "![" , "](#url#)" ] ,
2016-01-06 15:46:26 +01:00
table : [ "" , "\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n" ] ,
2015-11-03 17:16:08 +01:00
horizontalRule : [ "" , "\n\n-----\n\n" ]
2015-11-03 11:36:24 +01:00
} ;
2016-01-25 14:14:46 +01:00
var promptTexts = {
2016-01-26 10:39:27 +01:00
link : "URL for the link:" ,
image : "URL of the image:"
2016-01-25 14:14:46 +01:00
} ;
2015-11-29 21:11:54 +01:00
var blockStyles = {
"bold" : "**" ,
2016-01-20 00:09:19 +01:00
"code" : "```" ,
2015-11-29 21:11:54 +01:00
"italic" : "*"
} ;
2015-06-19 22:09:28 +02:00
/ * *
2015-06-22 22:26:05 +02:00
* Interface of SimpleMDE .
2015-06-19 22:09:28 +02:00
* /
2015-06-22 22:26:05 +02:00
function SimpleMDE ( options ) {
2015-09-20 03:42:20 +02:00
// Handle options parameter
2015-06-19 22:43:21 +02:00
options = options || { } ;
2015-09-04 01:01:47 +02:00
2015-09-20 03:42:20 +02:00
2015-10-07 22:52:14 +02:00
// Used later to refer to it"s parent
2015-09-04 00:59:50 +02:00
options . parent = this ;
2015-09-25 22:21:39 +02:00
2015-09-20 03:42:20 +02:00
// Check if Font Awesome needs to be auto downloaded
var autoDownloadFA = true ;
2015-09-25 22:21:39 +02:00
if ( options . autoDownloadFontAwesome === false ) {
2015-09-20 03:42:20 +02:00
autoDownloadFA = false ;
}
2015-09-25 22:21:39 +02:00
if ( options . autoDownloadFontAwesome !== true ) {
2015-09-20 03:42:20 +02:00
var styleSheets = document . styleSheets ;
for ( var i = 0 ; i < styleSheets . length ; i ++ ) {
if ( ! styleSheets [ i ] . href )
continue ;
2015-09-25 22:21:39 +02:00
if ( styleSheets [ i ] . href . indexOf ( "//maxcdn.bootstrapcdn.com/font-awesome/" ) > - 1 ) {
2015-09-20 03:42:20 +02:00
autoDownloadFA = false ;
}
}
}
2015-09-25 22:21:39 +02:00
if ( autoDownloadFA ) {
2015-09-20 03:42:20 +02:00
var link = document . createElement ( "link" ) ;
link . rel = "stylesheet" ;
link . href = "https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" ;
document . getElementsByTagName ( "head" ) [ 0 ] . appendChild ( link ) ;
}
2015-06-19 22:09:28 +02:00
2015-09-04 00:59:50 +02:00
// Find the textarea to use
2015-08-11 19:04:59 +02:00
if ( options . element ) {
2015-06-19 22:43:21 +02:00
this . element = options . element ;
2015-09-02 05:37:54 +02:00
} else if ( options . element === null ) {
2015-09-02 03:31:32 +02:00
// This means that the element option was specified, but no element was found
console . log ( "SimpleMDE: Error. No element was found." ) ;
return ;
}
2015-07-21 15:28:36 +02:00
2015-09-20 03:42:20 +02:00
2015-12-05 07:18:40 +01:00
// Handle toolbar
if ( options . toolbar === undefined ) {
// Initialize
options . toolbar = [ ] ;
2015-06-19 22:09:28 +02:00
2015-12-05 07:18:40 +01:00
// Loop over the built in buttons, to get the preferred order
for ( var key in toolbarBuiltInButtons ) {
if ( toolbarBuiltInButtons . hasOwnProperty ( key ) ) {
if ( key . indexOf ( "separator-" ) != - 1 ) {
options . toolbar . push ( "|" ) ;
}
if ( toolbarBuiltInButtons [ key ] . default === true || ( options . showIcons && options . showIcons . constructor === Array && options . showIcons . indexOf ( key ) != - 1 ) ) {
options . toolbar . push ( key ) ;
}
}
}
}
// Handle status bar
2015-10-07 22:52:14 +02:00
if ( ! options . hasOwnProperty ( "status" ) ) {
options . status = [ "autosave" , "lines" , "words" , "cursor" ] ;
2015-06-19 22:43:21 +02:00
}
2015-06-19 22:09:28 +02:00
2015-09-20 03:42:20 +02:00
2015-09-04 00:59:50 +02:00
// Add default preview rendering function
2015-09-04 00:37:44 +02:00
if ( ! options . previewRender ) {
2015-09-04 00:59:50 +02:00
options . previewRender = function ( plainText ) {
2015-10-07 22:52:14 +02:00
// Note: "this" refers to the options object
2015-09-04 00:59:50 +02:00
return this . parent . markdown ( plainText ) ;
2015-10-07 22:52:14 +02:00
} ;
2015-09-02 21:59:11 +02:00
}
2015-09-20 03:42:20 +02:00
2015-09-12 09:03:48 +02:00
// Set default options for parsing config
2016-01-20 00:09:19 +01:00
options . parsingConfig = extend ( {
highlightFormatting : true // needed for toggleCodeBlock to detect types of code
} , options . parsingConfig || { } ) ;
2015-09-12 09:03:48 +02:00
2015-11-03 17:16:08 +01:00
2015-11-03 18:31:22 +01:00
// Merging the insertTexts, with the given options
options . insertTexts = extend ( { } , insertTexts , options . insertTexts || { } ) ;
2015-11-03 11:36:24 +01:00
2015-09-20 03:42:20 +02:00
2016-01-25 14:14:46 +01:00
// Merging the promptTexts, with the given options
2016-01-26 10:39:27 +01:00
options . promptTexts = promptTexts ;
2016-01-25 14:14:46 +01:00
2015-11-29 21:11:54 +01:00
// Merging the blockStyles, with the given options
options . blockStyles = extend ( { } , blockStyles , options . blockStyles || { } ) ;
2016-01-07 10:38:19 +01:00
// Merging the shortcuts, with the given options
options . shortcuts = extend ( { } , shortcuts , options . shortcuts || { } ) ;
2015-11-19 21:47:15 +01:00
// Change unique_id to uniqueId for backwards compatibility
2015-11-30 10:18:26 +01:00
if ( options . autosave != undefined && options . autosave . unique _id != undefined && options . autosave . unique _id != "" )
2015-11-19 21:47:15 +01:00
options . autosave . uniqueId = options . autosave . unique _id ;
2015-09-04 00:59:50 +02:00
// Update this options
2015-08-11 19:04:59 +02:00
this . options = options ;
2015-06-19 22:09:28 +02:00
2015-09-20 03:42:20 +02:00
2015-09-04 00:59:50 +02:00
// Auto render
2015-06-26 21:01:02 +02:00
this . render ( ) ;
2015-08-11 10:25:29 +02:00
2015-09-20 03:42:20 +02:00
2015-08-11 19:04:59 +02:00
// The codemirror component is only available after rendering
// so, the setter for the initialValue can only run after
// the element has been rendered
2015-12-05 07:31:27 +01:00
if ( options . initialValue && ( ! this . options . autosave || this . options . autosave . foundSavedValue !== true ) ) {
2015-08-11 19:04:59 +02:00
this . value ( options . initialValue ) ;
}
2015-06-19 22:09:28 +02:00
}
/ * *
* Default markdown render .
* /
2015-09-02 21:59:11 +02:00
SimpleMDE . prototype . markdown = function ( text ) {
2015-10-15 12:01:16 +02:00
if ( marked ) {
2015-09-25 23:47:24 +02:00
// Initialize
var markedOptions = { } ;
2015-09-26 00:10:10 +02:00
2015-09-01 06:29:02 +02:00
// Update options
2016-02-25 21:48:05 +01:00
if ( this . options && this . options . renderingConfig && this . options . renderingConfig . singleLineBreaks === false ) {
markedOptions . breaks = false ;
} else {
2015-09-25 23:47:24 +02:00
markedOptions . breaks = true ;
2015-09-01 06:53:32 +02:00
}
2015-09-26 00:10:10 +02:00
2015-09-25 23:47:24 +02:00
if ( this . options && this . options . renderingConfig && this . options . renderingConfig . codeSyntaxHighlighting === true && window . hljs ) {
markedOptions . highlight = function ( code ) {
2015-10-07 22:52:14 +02:00
return window . hljs . highlightAuto ( code ) . value ;
} ;
2015-09-25 23:47:24 +02:00
}
2015-09-26 00:10:10 +02:00
2015-09-25 23:47:24 +02:00
// Set options
marked . setOptions ( markedOptions ) ;
2015-09-26 00:10:10 +02:00
2015-09-25 23:47:24 +02:00
// Return
2015-06-19 22:43:21 +02:00
return marked ( text ) ;
}
2015-06-19 22:09:28 +02:00
} ;
/ * *
* Render editor to the given element .
* /
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . render = function ( el ) {
2015-08-11 19:04:59 +02:00
if ( ! el ) {
2015-10-07 22:52:14 +02:00
el = this . element || document . getElementsByTagName ( "textarea" ) [ 0 ] ;
2015-06-19 22:43:21 +02:00
}
2015-08-11 19:04:59 +02:00
if ( this . _rendered && this . _rendered === el ) {
2015-06-19 22:43:21 +02:00
// Already rendered.
return ;
}
this . element = el ;
var options = this . options ;
var self = this ;
var keyMaps = { } ;
2016-01-07 10:38:19 +01:00
for ( var key in options . shortcuts ) {
// null stands for "do not bind this command"
if ( options . shortcuts [ key ] !== null && bindings [ key ] !== null ) {
( function ( key ) {
keyMaps [ fixShortcut ( options . shortcuts [ key ] ) ] = function ( ) {
bindings [ key ] ( self ) ;
} ;
} ) ( key ) ;
}
2015-06-19 22:43:21 +02:00
}
keyMaps [ "Enter" ] = "newlineAndIndentContinueMarkdownList" ;
2015-09-12 09:03:48 +02:00
keyMaps [ "Tab" ] = "tabAndIndentMarkdownList" ;
keyMaps [ "Shift-Tab" ] = "shiftTabAndUnindentMarkdownList" ;
2015-08-08 20:14:04 +02:00
keyMaps [ "Esc" ] = function ( cm ) {
2015-09-17 07:42:31 +02:00
if ( cm . getOption ( "fullScreen" ) ) toggleFullScreen ( self ) ;
2015-08-08 20:14:04 +02:00
} ;
2015-07-21 15:28:36 +02:00
2015-12-05 02:48:26 +01:00
document . addEventListener ( "keydown" , function ( e ) {
e = e || window . event ;
if ( e . keyCode == 27 ) {
if ( self . codemirror . getOption ( "fullScreen" ) ) toggleFullScreen ( self ) ;
}
} , false ) ;
2015-09-12 09:03:48 +02:00
var mode , backdrop ;
if ( options . spellChecker !== false ) {
mode = "spell-checker" ;
backdrop = options . parsingConfig ;
backdrop . name = "gfm" ;
backdrop . gitHubSpice = false ;
2016-06-08 04:27:53 +02:00
CodeMirrorSpellChecker ( {
codeMirrorInstance : CodeMirror
} ) ;
2015-09-12 09:03:48 +02:00
} else {
mode = options . parsingConfig ;
mode . name = "gfm" ;
mode . gitHubSpice = false ;
2015-07-21 06:26:47 +02:00
}
2015-07-21 15:28:36 +02:00
2015-06-19 22:43:21 +02:00
this . codemirror = CodeMirror . fromTextArea ( el , {
2015-07-21 06:26:47 +02:00
mode : mode ,
backdrop : backdrop ,
2015-09-17 06:20:37 +02:00
theme : "paper" ,
2015-06-26 21:44:01 +02:00
tabSize : ( options . tabSize != undefined ) ? options . tabSize : 2 ,
2015-07-21 05:19:39 +02:00
indentUnit : ( options . tabSize != undefined ) ? options . tabSize : 2 ,
2015-06-26 19:53:24 +02:00
indentWithTabs : ( options . indentWithTabs === false ) ? false : true ,
2015-06-26 21:09:17 +02:00
lineNumbers : false ,
2015-06-26 19:53:24 +02:00
autofocus : ( options . autofocus === true ) ? true : false ,
2015-06-19 22:43:21 +02:00
extraKeys : keyMaps ,
2015-09-25 22:21:39 +02:00
lineWrapping : ( options . lineWrapping === false ) ? false : true ,
2015-12-09 00:06:38 +01:00
allowDropFileTypes : [ "text/plain" ] ,
2016-03-25 16:56:44 +01:00
placeholder : options . placeholder || el . getAttribute ( "placeholder" ) || "" ,
styleSelectedText : ( options . styleSelectedText != undefined ) ? options . styleSelectedText : true
2015-06-19 22:43:21 +02:00
} ) ;
2016-02-10 21:00:11 +01:00
if ( options . forceSync === true ) {
2016-02-10 11:56:39 +01:00
var cm = this . codemirror ;
cm . on ( "change" , function ( ) {
cm . save ( ) ;
} ) ;
}
2016-01-24 07:10:25 +01:00
this . gui = { } ;
2015-08-11 19:04:59 +02:00
if ( options . toolbar !== false ) {
2016-01-24 07:10:25 +01:00
this . gui . toolbar = this . createToolbar ( ) ;
2015-06-19 22:43:21 +02:00
}
2016-01-22 20:02:39 +01:00
if ( options . status !== false ) {
2016-01-24 07:10:25 +01:00
this . gui . statusbar = this . createStatusbar ( ) ;
2015-06-19 22:43:21 +02:00
}
2015-08-11 19:04:59 +02:00
if ( options . autosave != undefined && options . autosave . enabled === true ) {
2015-06-26 22:33:28 +02:00
this . autosave ( ) ;
}
2015-09-02 03:26:52 +02:00
2016-01-24 07:10:25 +01:00
this . gui . sideBySide = this . createSideBySide ( ) ;
2015-06-19 22:43:21 +02:00
this . _rendered = this . element ;
2015-06-19 22:09:28 +02:00
} ;
2016-03-15 02:59:16 +01:00
// 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.
function isLocalStorageAvailable ( ) {
if ( typeof localStorage === "object" ) {
try {
localStorage . setItem ( "smde_localStorage" , 1 ) ;
localStorage . removeItem ( "smde_localStorage" ) ;
2016-03-15 02:59:59 +01:00
} catch ( e ) {
2016-03-15 02:59:16 +01:00
return false ;
}
} else {
return false ;
}
2016-03-15 02:59:59 +01:00
2016-03-15 02:59:16 +01:00
return true ;
}
2015-06-26 22:33:28 +02:00
SimpleMDE . prototype . autosave = function ( ) {
2016-03-15 02:59:16 +01:00
if ( isLocalStorageAvailable ( ) ) {
2015-11-20 00:22:03 +01:00
var simplemde = this ;
2015-07-21 15:28:36 +02:00
2015-11-20 00:22:03 +01:00
if ( this . options . autosave . uniqueId == undefined || this . options . autosave . uniqueId == "" ) {
console . log ( "SimpleMDE: You must set a uniqueId to use the autosave feature" ) ;
return ;
}
2015-07-21 15:28:36 +02:00
2015-11-20 00:22:03 +01:00
if ( simplemde . element . form != null && simplemde . element . form != undefined ) {
simplemde . element . form . addEventListener ( "submit" , function ( ) {
localStorage . removeItem ( "smde_" + simplemde . options . autosave . uniqueId ) ;
} ) ;
}
2015-07-21 15:28:36 +02:00
2015-11-20 00:22:03 +01:00
if ( this . options . autosave . loaded !== true ) {
2015-12-05 07:31:27 +01:00
if ( typeof localStorage . getItem ( "smde_" + this . options . autosave . uniqueId ) == "string" && localStorage . getItem ( "smde_" + this . options . autosave . uniqueId ) != "" ) {
2015-11-20 00:22:03 +01:00
this . codemirror . setValue ( localStorage . getItem ( "smde_" + this . options . autosave . uniqueId ) ) ;
2015-12-05 07:31:27 +01:00
this . options . autosave . foundSavedValue = true ;
}
2015-07-21 15:28:36 +02:00
2015-11-20 00:22:03 +01:00
this . options . autosave . loaded = true ;
}
2015-07-21 15:28:36 +02:00
2015-11-20 00:22:03 +01:00
localStorage . setItem ( "smde_" + this . options . autosave . uniqueId , simplemde . value ( ) ) ;
var el = document . getElementById ( "autosaved" ) ;
if ( el != null && el != undefined && el != "" ) {
var d = new Date ( ) ;
var hh = d . getHours ( ) ;
var m = d . getMinutes ( ) ;
var dd = "am" ;
var h = hh ;
if ( h >= 12 ) {
h = hh - 12 ;
dd = "pm" ;
}
if ( h == 0 ) {
h = 12 ;
}
m = m < 10 ? "0" + m : m ;
2015-07-21 15:28:36 +02:00
2015-11-20 00:22:03 +01:00
el . innerHTML = "Autosaved: " + h + ":" + m + " " + dd ;
2015-06-26 23:04:14 +02:00
}
2015-07-21 15:28:36 +02:00
2016-01-24 07:10:25 +01:00
this . autosaveTimeoutId = setTimeout ( function ( ) {
2015-11-20 00:22:03 +01:00
simplemde . autosave ( ) ;
} , this . options . autosave . delay || 10000 ) ;
} else {
console . log ( "SimpleMDE: localStorage not available, cannot autosave" ) ;
2015-06-26 23:04:14 +02:00
}
2015-11-20 00:22:03 +01:00
} ;
2015-07-21 15:28:36 +02:00
2015-11-20 00:22:03 +01:00
SimpleMDE . prototype . clearAutosavedValue = function ( ) {
2016-03-15 02:59:16 +01:00
if ( isLocalStorageAvailable ( ) ) {
2016-01-13 07:46:35 +01:00
if ( this . options . autosave == undefined || this . options . autosave . uniqueId == undefined || this . options . autosave . uniqueId == "" ) {
console . log ( "SimpleMDE: You must set a uniqueId to clear the autosave value" ) ;
2015-11-20 00:22:03 +01:00
return ;
}
localStorage . removeItem ( "smde_" + this . options . autosave . uniqueId ) ;
} else {
console . log ( "SimpleMDE: localStorage not available, cannot autosave" ) ;
}
2015-06-26 22:33:28 +02:00
} ;
2015-09-10 08:29:00 +02:00
SimpleMDE . prototype . createSideBySide = function ( ) {
2015-09-01 08:40:33 +02:00
var cm = this . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
var preview = wrapper . nextSibling ;
2015-09-10 08:29:00 +02:00
if ( ! preview || ! /editor-preview-side/ . test ( preview . className ) ) {
2015-10-07 22:52:14 +02:00
preview = document . createElement ( "div" ) ;
preview . className = "editor-preview-side" ;
2015-09-01 08:40:33 +02:00
wrapper . parentNode . insertBefore ( preview , wrapper . nextSibling ) ;
}
// Syncs scroll editor -> preview
var cScroll = false ;
var pScroll = false ;
2015-10-07 22:52:14 +02:00
cm . on ( "scroll" , function ( v ) {
2015-09-02 03:26:52 +02:00
if ( cScroll ) {
cScroll = false ;
return ;
2015-10-07 22:52:14 +02:00
}
2015-09-02 03:26:52 +02:00
pScroll = true ;
2015-10-07 22:52:14 +02:00
var height = v . getScrollInfo ( ) . height - v . getScrollInfo ( ) . clientHeight ;
var ratio = parseFloat ( v . getScrollInfo ( ) . top ) / height ;
var move = ( preview . scrollHeight - preview . clientHeight ) * ratio ;
2015-09-01 08:40:33 +02:00
preview . scrollTop = move ;
} ) ;
// Syncs scroll preview -> editor
2015-10-07 22:52:14 +02:00
preview . onscroll = function ( ) {
2015-09-02 03:26:52 +02:00
if ( pScroll ) {
pScroll = false ;
return ;
2015-10-07 22:52:14 +02:00
}
2015-09-02 03:26:52 +02:00
cScroll = true ;
2015-10-07 22:52:14 +02:00
var height = preview . scrollHeight - preview . clientHeight ;
var ratio = parseFloat ( preview . scrollTop ) / height ;
var move = ( cm . getScrollInfo ( ) . height - cm . getScrollInfo ( ) . clientHeight ) * ratio ;
2015-09-01 08:40:33 +02:00
cm . scrollTo ( 0 , move ) ;
} ;
2016-01-24 07:10:25 +01:00
return preview ;
2015-10-07 22:52:14 +02:00
} ;
2015-09-01 08:40:33 +02:00
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . createToolbar = function ( items ) {
2015-06-19 22:43:21 +02:00
items = items || this . options . toolbar ;
2015-06-19 22:09:28 +02:00
2015-08-11 19:04:59 +02:00
if ( ! items || items . length === 0 ) {
2015-06-19 22:43:21 +02:00
return ;
}
2015-10-07 22:52:14 +02:00
var i ;
for ( i = 0 ; i < items . length ; i ++ ) {
2015-09-02 03:26:52 +02:00
if ( toolbarBuiltInButtons [ items [ i ] ] != undefined ) {
2015-08-18 15:37:42 +02:00
items [ i ] = toolbarBuiltInButtons [ items [ i ] ] ;
2015-08-17 23:34:05 +02:00
}
}
2015-06-19 22:43:21 +02:00
2015-10-07 22:52:14 +02:00
var bar = document . createElement ( "div" ) ;
bar . className = "editor-toolbar" ;
2015-06-19 22:43:21 +02:00
var self = this ;
2016-01-22 20:16:54 +01:00
var toolbarData = { } ;
2015-08-07 23:32:53 +02:00
self . toolbar = items ;
2015-06-19 22:43:21 +02:00
2015-10-07 22:52:14 +02:00
for ( i = 0 ; i < items . length ; i ++ ) {
2015-07-14 19:43:33 +02:00
if ( items [ i ] . name == "guide" && self . options . toolbarGuideIcon === false )
continue ;
2015-09-25 22:21:39 +02:00
2015-09-25 22:33:35 +02:00
if ( self . options . hideIcons && self . options . hideIcons . indexOf ( items [ i ] . name ) != - 1 )
2015-09-24 22:03:20 +02:00
continue ;
2015-11-03 17:16:08 +01:00
2015-10-08 04:13:38 +02:00
// Fullscreen does not work well on mobile devices (even tablets)
// In the future, hopefully this can be resolved
if ( ( items [ i ] . name == "fullscreen" || items [ i ] . name == "side-by-side" ) && isMobile ( ) )
continue ;
2015-07-21 15:28:36 +02:00
2016-01-22 20:16:54 +01:00
// Don't include trailing separators
if ( items [ i ] === "|" ) {
var nonSeparatorIconsFollow = false ;
for ( var x = ( i + 1 ) ; x < items . length ; x ++ ) {
2016-02-25 21:53:08 +01:00
if ( items [ x ] !== "|" && ( ! self . options . hideIcons || self . options . hideIcons . indexOf ( items [ x ] . name ) == - 1 ) ) {
2016-01-22 20:16:54 +01:00
nonSeparatorIconsFollow = true ;
}
}
if ( ! nonSeparatorIconsFollow )
continue ;
}
// Create the icon and append to the toolbar
2015-06-19 22:43:21 +02:00
( function ( item ) {
var el ;
2015-10-07 22:52:14 +02:00
if ( item === "|" ) {
2015-06-19 22:43:21 +02:00
el = createSep ( ) ;
} else {
2016-01-07 10:38:19 +01:00
el = createIcon ( item , self . options . toolbarTips , self . options . shortcuts ) ;
2015-06-19 22:43:21 +02:00
}
// bind events, special for info
2015-08-11 19:04:59 +02:00
if ( item . action ) {
2015-10-07 22:52:14 +02:00
if ( typeof item . action === "function" ) {
2016-06-03 15:07:15 +02:00
el . onclick = function ( e ) {
2016-06-03 15:09:33 +02:00
e . preventDefault ( ) ;
2015-06-19 22:43:21 +02:00
item . action ( self ) ;
} ;
2015-10-07 22:52:14 +02:00
} else if ( typeof item . action === "string" ) {
2015-06-19 22:43:21 +02:00
el . href = item . action ;
2015-10-07 22:52:14 +02:00
el . target = "_blank" ;
2015-06-19 22:43:21 +02:00
}
}
2016-01-22 20:16:54 +01:00
toolbarData [ item . name || item ] = el ;
2015-06-19 22:43:21 +02:00
bar . appendChild ( el ) ;
} ) ( items [ i ] ) ;
2015-06-19 22:09:28 +02:00
}
2015-07-21 15:28:36 +02:00
2016-01-22 20:16:54 +01:00
self . toolbarElements = toolbarData ;
2015-06-19 22:09:28 +02:00
2015-06-19 22:43:21 +02:00
var cm = this . codemirror ;
2015-10-07 22:52:14 +02:00
cm . on ( "cursorActivity" , function ( ) {
2015-06-19 22:43:21 +02:00
var stat = getState ( cm ) ;
2016-01-22 20:16:54 +01:00
for ( var key in toolbarData ) {
2015-06-19 22:43:21 +02:00
( function ( key ) {
2016-01-22 20:16:54 +01:00
var el = toolbarData [ key ] ;
2015-08-11 19:04:59 +02:00
if ( stat [ key ] ) {
2015-10-07 22:52:14 +02:00
el . className += " active" ;
2015-09-01 08:40:33 +02:00
} else if ( key != "fullscreen" && key != "side-by-side" ) {
2015-10-07 22:52:14 +02:00
el . className = el . className . replace ( /\s*active\s*/g , "" ) ;
2015-06-19 22:43:21 +02:00
}
} ) ( key ) ;
}
} ) ;
var cmWrapper = cm . getWrapperElement ( ) ;
cmWrapper . parentNode . insertBefore ( bar , cmWrapper ) ;
return bar ;
2015-06-19 22:09:28 +02:00
} ;
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . createStatusbar = function ( status ) {
2016-01-22 20:02:39 +01:00
// Initialize
2015-06-19 22:43:21 +02:00
status = status || this . options . status ;
2015-10-07 22:52:14 +02:00
var options = this . options ;
2016-01-22 20:02:39 +01:00
var cm = this . codemirror ;
// Make sure the status variable is valid
if ( ! status || status . length === 0 )
return ;
2015-06-19 22:43:21 +02:00
2016-01-22 20:02:39 +01:00
// Set up the built-in items
var items = [ ] ;
var i , onUpdate , defaultValue ;
2015-06-19 22:43:21 +02:00
2016-01-21 13:12:30 +01:00
for ( i = 0 ; i < status . length ; i ++ ) {
2016-01-22 20:02:39 +01:00
// Reset some values
onUpdate = undefined ;
defaultValue = undefined ;
2016-01-21 13:12:30 +01:00
2016-01-22 20:02:39 +01:00
// Handle if custom or not
if ( typeof status [ i ] === "object" ) {
items . push ( {
className : status [ i ] . className ,
defaultValue : status [ i ] . defaultValue ,
onUpdate : status [ i ] . onUpdate
} ) ;
} else {
var name = status [ i ] ;
2016-01-21 13:12:30 +01:00
2016-01-22 20:02:39 +01:00
if ( name === "words" ) {
defaultValue = function ( el ) {
el . innerHTML = "0" ;
} ;
onUpdate = function ( el ) {
el . innerHTML = wordCount ( cm . getValue ( ) ) ;
} ;
} else if ( name === "lines" ) {
defaultValue = function ( el ) {
el . innerHTML = "0" ;
} ;
onUpdate = function ( el ) {
el . innerHTML = cm . lineCount ( ) ;
} ;
} else if ( name === "cursor" ) {
defaultValue = function ( el ) {
el . innerHTML = "0:0" ;
} ;
onUpdate = function ( el ) {
var pos = cm . getCursor ( ) ;
el . innerHTML = pos . line + ":" + pos . ch ;
} ;
} else if ( name === "autosave" ) {
defaultValue = function ( el ) {
if ( options . autosave != undefined && options . autosave . enabled === true ) {
el . setAttribute ( "id" , "autosaved" ) ;
}
} ;
}
items . push ( {
className : name ,
defaultValue : defaultValue ,
onUpdate : onUpdate
} ) ;
2016-01-21 13:12:30 +01:00
}
}
2016-01-22 20:02:39 +01:00
// Create element for the status bar
2016-01-21 13:12:30 +01:00
var bar = document . createElement ( "div" ) ;
bar . className = "editor-statusbar" ;
2016-01-22 20:02:39 +01:00
// Create a new span for each item
for ( i = 0 ; i < items . length ; i ++ ) {
// Store in temporary variable
var item = items [ i ] ;
// Create span element
var el = document . createElement ( "span" ) ;
el . className = item . className ;
// Ensure the defaultValue is a function
if ( typeof item . defaultValue === "function" ) {
item . defaultValue ( el ) ;
}
// Ensure the onUpdate is a function
if ( typeof item . onUpdate === "function" ) {
// Create a closure around the span of the current action, then execute the onUpdate handler
this . codemirror . on ( "update" , ( function ( el , item ) {
return function ( ) {
item . onUpdate ( el ) ;
} ;
} ( el , item ) ) ) ;
2016-01-21 13:12:30 +01:00
}
2016-01-22 20:02:39 +01:00
// Append the item to the status bar
bar . appendChild ( el ) ;
2015-06-19 22:43:21 +02:00
}
2015-07-21 15:28:36 +02:00
2016-01-22 20:02:39 +01:00
// Insert the status bar into the DOM
2015-06-19 22:43:21 +02:00
var cmWrapper = this . codemirror . getWrapperElement ( ) ;
cmWrapper . parentNode . insertBefore ( bar , cmWrapper . nextSibling ) ;
return bar ;
2015-06-19 22:09:28 +02:00
} ;
/ * *
* Get or set the text content .
* /
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . value = function ( val ) {
2015-08-11 19:04:59 +02:00
if ( val === undefined ) {
2015-07-21 15:28:36 +02:00
return this . codemirror . getValue ( ) ;
} else {
2015-06-19 22:43:21 +02:00
this . codemirror . getDoc ( ) . setValue ( val ) ;
return this ;
}
2015-06-19 22:09:28 +02:00
} ;
/ * *
* Bind static methods for exports .
* /
2015-06-22 22:26:05 +02:00
SimpleMDE . toggleBold = toggleBold ;
SimpleMDE . toggleItalic = toggleItalic ;
2015-09-01 07:51:40 +02:00
SimpleMDE . toggleStrikethrough = toggleStrikethrough ;
2015-06-22 22:26:05 +02:00
SimpleMDE . toggleBlockquote = toggleBlockquote ;
2015-08-12 18:23:09 +02:00
SimpleMDE . toggleHeadingSmaller = toggleHeadingSmaller ;
SimpleMDE . toggleHeadingBigger = toggleHeadingBigger ;
2015-09-01 07:40:11 +02:00
SimpleMDE . toggleHeading1 = toggleHeading1 ;
SimpleMDE . toggleHeading2 = toggleHeading2 ;
SimpleMDE . toggleHeading3 = toggleHeading3 ;
2015-07-14 19:34:22 +02:00
SimpleMDE . toggleCodeBlock = toggleCodeBlock ;
2015-07-14 18:52:28 +02:00
SimpleMDE . toggleUnorderedList = toggleUnorderedList ;
2015-06-22 22:26:05 +02:00
SimpleMDE . toggleOrderedList = toggleOrderedList ;
2016-01-08 14:44:43 +01:00
SimpleMDE . cleanBlock = cleanBlock ;
2015-06-22 22:26:05 +02:00
SimpleMDE . drawLink = drawLink ;
SimpleMDE . drawImage = drawImage ;
2015-11-24 18:54:41 +01:00
SimpleMDE . drawTable = drawTable ;
2015-07-14 19:34:22 +02:00
SimpleMDE . drawHorizontalRule = drawHorizontalRule ;
2015-06-22 22:26:05 +02:00
SimpleMDE . undo = undo ;
SimpleMDE . redo = redo ;
SimpleMDE . togglePreview = togglePreview ;
2015-09-01 08:40:33 +02:00
SimpleMDE . toggleSideBySide = toggleSideBySide ;
2015-06-22 22:26:05 +02:00
SimpleMDE . toggleFullScreen = toggleFullScreen ;
2015-06-19 22:09:28 +02:00
/ * *
* Bind instance methods for exports .
* /
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . toggleBold = function ( ) {
2015-06-19 22:43:21 +02:00
toggleBold ( this ) ;
2015-06-19 22:09:28 +02:00
} ;
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . toggleItalic = function ( ) {
2015-06-19 22:43:21 +02:00
toggleItalic ( this ) ;
2015-06-19 22:09:28 +02:00
} ;
2015-09-01 07:51:40 +02:00
SimpleMDE . prototype . toggleStrikethrough = function ( ) {
toggleStrikethrough ( this ) ;
} ;
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . toggleBlockquote = function ( ) {
2015-06-19 22:43:21 +02:00
toggleBlockquote ( this ) ;
2015-06-19 22:09:28 +02:00
} ;
2015-08-12 18:23:09 +02:00
SimpleMDE . prototype . toggleHeadingSmaller = function ( ) {
toggleHeadingSmaller ( this ) ;
} ;
SimpleMDE . prototype . toggleHeadingBigger = function ( ) {
toggleHeadingBigger ( this ) ;
} ;
2015-09-01 07:40:11 +02:00
SimpleMDE . prototype . toggleHeading1 = function ( ) {
toggleHeading1 ( this ) ;
} ;
SimpleMDE . prototype . toggleHeading2 = function ( ) {
toggleHeading2 ( this ) ;
} ;
SimpleMDE . prototype . toggleHeading3 = function ( ) {
toggleHeading3 ( this ) ;
} ;
2015-07-14 19:34:22 +02:00
SimpleMDE . prototype . toggleCodeBlock = function ( ) {
toggleCodeBlock ( this ) ;
} ;
2015-07-14 18:52:28 +02:00
SimpleMDE . prototype . toggleUnorderedList = function ( ) {
toggleUnorderedList ( this ) ;
2015-06-19 22:09:28 +02:00
} ;
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . toggleOrderedList = function ( ) {
2015-06-19 22:43:21 +02:00
toggleOrderedList ( this ) ;
2015-06-19 22:09:28 +02:00
} ;
2016-01-08 14:44:43 +01:00
SimpleMDE . prototype . cleanBlock = function ( ) {
cleanBlock ( this ) ;
} ;
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . drawLink = function ( ) {
2015-06-19 22:43:21 +02:00
drawLink ( this ) ;
2015-06-19 22:09:28 +02:00
} ;
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . drawImage = function ( ) {
2015-06-19 22:43:21 +02:00
drawImage ( this ) ;
2015-11-24 18:54:41 +01:00
} ;
SimpleMDE . prototype . drawTable = function ( ) {
drawTable ( this ) ;
2015-06-19 22:09:28 +02:00
} ;
2015-07-14 19:34:22 +02:00
SimpleMDE . prototype . drawHorizontalRule = function ( ) {
drawHorizontalRule ( this ) ;
} ;
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . undo = function ( ) {
2015-06-19 22:43:21 +02:00
undo ( this ) ;
2015-06-19 22:09:28 +02:00
} ;
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . redo = function ( ) {
2015-06-19 22:43:21 +02:00
redo ( this ) ;
2015-06-19 22:09:28 +02:00
} ;
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . togglePreview = function ( ) {
2015-06-19 22:43:21 +02:00
togglePreview ( this ) ;
2015-06-19 22:09:28 +02:00
} ;
2015-09-01 08:40:33 +02:00
SimpleMDE . prototype . toggleSideBySide = function ( ) {
toggleSideBySide ( this ) ;
} ;
2015-06-22 22:26:05 +02:00
SimpleMDE . prototype . toggleFullScreen = function ( ) {
2015-06-19 22:43:21 +02:00
toggleFullScreen ( this ) ;
2015-08-18 15:37:42 +02:00
} ;
2015-10-20 22:01:14 +02:00
SimpleMDE . prototype . isPreviewActive = function ( ) {
var cm = this . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
var preview = wrapper . lastChild ;
2015-11-03 17:16:08 +01:00
2015-10-20 22:01:14 +02:00
return /editor-preview-active/ . test ( preview . className ) ;
} ;
SimpleMDE . prototype . isSideBySideActive = function ( ) {
var cm = this . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
var preview = wrapper . nextSibling ;
2015-11-03 17:16:08 +01:00
2015-10-20 22:01:14 +02:00
return /editor-preview-active-side/ . test ( preview . className ) ;
} ;
SimpleMDE . prototype . isFullscreenActive = function ( ) {
var cm = this . codemirror ;
2015-11-03 17:16:08 +01:00
2015-10-20 22:01:14 +02:00
return cm . getOption ( "fullScreen" ) ;
} ;
2016-01-20 21:50:59 +01:00
SimpleMDE . prototype . getState = function ( ) {
var cm = this . codemirror ;
return getState ( cm ) ;
} ;
2016-01-24 07:10:25 +01:00
SimpleMDE . prototype . toTextArea = function ( ) {
var cm = this . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
2016-03-31 12:34:12 +02:00
if ( wrapper . parentNode ) {
if ( this . gui . toolbar ) {
wrapper . parentNode . removeChild ( this . gui . toolbar ) ;
}
if ( this . gui . statusbar ) {
wrapper . parentNode . removeChild ( this . gui . statusbar ) ;
}
if ( this . gui . sideBySide ) {
wrapper . parentNode . removeChild ( this . gui . sideBySide ) ;
}
}
2016-01-24 07:10:25 +01:00
cm . toTextArea ( ) ;
if ( this . autosaveTimeoutId ) {
clearTimeout ( this . autosaveTimeoutId ) ;
this . autosaveTimeoutId = undefined ;
this . clearAutosavedValue ( ) ;
}
} ;
2016-06-07 01:39:01 +02:00
module . exports = SimpleMDE ;